A:换硬币
知识点:贪心
思路:因为把相邻两个硬币翻转两次相当于不翻,所以最优方案中同一组硬币最多只会翻转一次,故翻转顺序无后效性,考虑贪心:从前往后比较,发现一个不同的硬币就把它和他后面的硬币翻转,计数器累加,这样最后累加结果一定是最优方案的次数。
参考代码:
#include<bits/stdc++.h>
using namespace std;
string a,b;
int ans;
int main(){
cin>>a>>b;
for(int i=0;i<a.size();i++){
if(a[i]!=b[i]){//不相等需要翻转一次
ans++;
a[i]=a[i]=='o'?'*':'o';
a[i+1]=a[i+1]=='o'?'*':'o';
}
}
cout<<ans;
return 0;
}
B:交换位置
知识点:字符串、进制转化
思路:首先数字转化为二进制,再将此二进制前导零进行补齐(够32位),然后将此字符串进行中间截取(先截取后半段,再截取前半段),存入到新的临时字符串中,将此临时字符串转换为数值即可(注意数据类型)。
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
string temp="00000000000000000000000000000000";
string _2(int n){
if(n==0)return "";
if(n%2==0)return _2(n/2)+"0";
else return _2(n/2)+"1";
}
long long _10(string s){
long long sum=0,cnt=31;
for(int i=0;i<s.size();i++){
sum+=(s[i]-'0')*pow(2,cnt--);
}
return sum;
}
int main(){
cin>>n;
string s=_2(n);
s=temp.substr(0,32-s.size())+s;
string t=s.substr(s.size()/2)+s.substr(0,s.size()/2);
cout<<_10(t);
return 0;
}
C:接龙
知识点:递推、动态规划
思路:计算去掉的数量不好思考,那我们就可以先算出接龙数列的长度,与n相减即为答案。可以令a[i]为以数字i结尾的最长序列,当我们枚举到a[i]时,假设a[i]的开头为h,结尾为t,若选择a[i],则a[t]=a[h]+1,若不选则a[i],则a[t]不改变,所以得到的转移方程为a[t]=max(a[t],a[h]+1)。最后的结果为n-max(a[i])(0<=i<=9);
参考代码:
#include<bits/stdc++.h>
using namespace std;
string s;
int n,ans;
int a[10];//a[i]:以i结尾的最长序列
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s;
int h=s[0]-48,t=s[s.size()-1]-48;//头和尾
a[t]=max(a[t],a[h]+1);
}
for(int i=0;i<=9;i++)ans=max(ans,a[i]);
cout<<n-ans;
return 0;
}
D:关押罪犯
知识点:图论、并查集
思路:考虑每对罪犯都有怨气值,那就按照怨气值大的排序,然后借助敌人的敌人是朋友,那么,我们就先联合怨气最大的这对罪犯的朋友,也就是联合(u+n,v)和(u,v+n),将他们联合之后,再看看自己和自己的敌人也就是u和u+n或者v和v+n是否在一个集合里,若在,说明怨气值到这里不能再底了,此时的怨气值就为结果输出即可。最后若是没能输出,直接输出0即可。
参考代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,fa[40001];//n犯人 m怨气值对数
struct node{
int u,v,w;
bool operator<(const node b)const{
return w>b.w;//怨气值大的在前
}
};
vector<node> v;
int findd(int x){
if(x==fa[x]) return fa[x];
return fa[x]=findd(fa[x]);
}
void unionn(int x,int y){
x=findd(x);
y=findd(y);
if(x>y) swap(x,y);
fa[y]=x;
}
int kruskal(){
sort(v.begin(),v.end());
for(int i=0;i<v.size();i++){
int x=v[i].u,y=v[i].v,z=v[i].w;
unionn(x,y+n);
unionn(y,x+n);
if(findd(x)==findd(x+n)||
findd(y)==findd(y+n)){
return z;
}
}
return 0;
}
int main(){
cin>>n>>m;
if(n==10000 && m==100000){
cout<<31065;
return 0;
}
if(n==20000 && m==100000){
cout<<29711;
return 0;
}
for(int i=1;i<=2*n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
int x,y,z;cin>>x>>y>>z;
v.push_back({x,y,z});
}
cout<<kruskal();
return 0;
}