Acwing 1208. 翻硬币
题目链接:1208. 翻硬币 - AcWing题库
标签:递归
思路:穷举翻硬币的每种情况,若符合条件,更新翻的次数;否则,不变。
注意:剪枝,若在操作完前面的区域,以后对该区域不再操作了,但该区域不符合条件,可以直接return减少后续操作。
AC代码:
#include<iostream>
#include<cstring>
using namespace std;
char coin[120]={'1'};
char result[120]={'1'};
int len;
int ans=120;
int cnt=0;
bool check()
{
for(int i=1;i<=len;i++)
if(coin[i]!=result[i]) return false;
return true;
}
bool check2(int u)
{
for(int i=1;i<u;++i)
{
if(coin[i]!=result[i]) return false;
}
return true;
}
void work(int x)
{
if(coin[x]=='o') coin[x]='*';
else coin[x]='o';
if(coin[x+1]=='o') coin[x+1]='*';
else coin[x+1]='o';
}
void dfs(int u)
{
if(u>=len)
{
if(check()&&cnt<ans)
{
ans=cnt;
}
return;
}
//剪枝
if(check2(u)==false) return;
//不翻第u个硬币
dfs(u+1);
//翻第u个硬币
work(u);
cnt++;
dfs(u+1);
cnt--;
work(u);
}
int main()
{
cin>>coin+1;
cin>>result+1;
len=strlen(coin)-1;
dfs(1);
cout<<ans<<endl;
return 0;
}
做法二:模拟
如果第1个硬币不一样,那么一定要翻一下第1、2 个硬币,才可以达到目标
同理,当前i-1个硬币与结果相同时,如果第i个硬币与目标不同,那么一定要翻一下第i个和第i+1个硬币才可以达到目标
即从第1个到第n-1个硬币遍历,如果不一样,则翻一次,ans++;
AC代码:
#include<iostream>
#include<cstring>
using namespace std;
char coin[105];
char result[105];
int main()
{
cin>>coin;
cin>>result;
int len=strlen(coin);
int ans=0;
for(int i=0;i<len-1;++i)
{
if(coin[i]!=result[i])
{
if(coin[i+1]=='o') coin[i+1]='*';
else coin[i+1]='o';
ans++;
}
}
cout<<ans<<endl;
return 0;
}
Acwing 116. 飞行员兄弟
标签:递归
思路:暴力枚举(同上)
AC代码:
#include<iostream>
using namespace std;
char map[5][5];
bool vis[5][5];
int ans[20][2],cur[20][2];
int cnt=0,cnt_ans=20;
char ch;
void work(int x,int y)
{
for(int i=1;i<=4;++i)
{
if(map[i][y]=='+') map[i][y]='-';
else map[i][y]='+';
if(map[x][i]=='+') map[x][i]='-';
else map[x][i]='+';
}
//由于map[x][y]翻转了两次,再将他翻回来
if(map[x][y]=='+') map[x][y]='-';
else map[x][y]='+';
}
bool check()
{
for(int i=1;i<=4;++i)
{
for(int j=1;j<=4;++j)
{
if(map[i][j]!='-') return false;
}
}
return true;
}
void dfs(int x,int y)
{
if(x>4)
{
if(check()&&cnt<cnt_ans)
{
for(int i=0;i<cnt;++i)
{
ans[i][0]=cur[i][0];
ans[i][1]=cur[i][1];
}
cnt_ans=cnt;
}
return;
}
vis[x][y]=false;
if(y<4) dfs(x,y+1);
else dfs(x+1,1);
vis[x][y]=true;
work(x,y);
cur[cnt][0]=x;
cur[cnt++][1]=y;
if(y<4) dfs(x,y+1);
else dfs(x+1,1);
work(x,y);
cnt--;
}
int main()
{
for(int i=1;i<=4;++i)
{
for(int j=1;j<=4;++j)
{
cin>>map[i][j];
}
}
dfs(1,1);
cout<<cnt_ans<<endl;
for(int i=0;i<cnt_ans;++i)
{
cout<<ans[i][0]<<" "<<ans[i][1]<<endl;
}
return 0;
}
Acwing 95. 费解的开关
题目链接:95. 费解的开关 - AcWing题库
标签:递归
思路:暴力枚举
AC代码:
#include<iostream>
using namespace std;
char ch[10];
int map[7][7];
int dir[5][2]={0,0,1,0,-1,0,0,1,0,-1};
int cnt=0;
int ans=40;
void work(int x,int y)
{
for(int i=0;i<5;++i)
{
map[x+dir[i][0]][y+dir[i][1]] ^=1;
}
}
bool check()
{
for(int i=1;i<=5;++i)
{
for(int j=1;j<=5;++j)
{
if(map[i][j]!=1) return false;
}
}
return true;
}
bool check2(int x)
{
int tmp=1;
for(int i=1;i<=5;++i)
{
tmp &= map[x-2][i];
}
if(tmp==0) return true;
return false;
}
void dfs(int x,int y)
{
if(x>5)
{
if(check()&&cnt<ans)
{
ans=cnt;
}
return;
}
//x,y不操作
if(y<5) dfs(x,y+1);
else dfs(x+1,1);
//剪枝:如果都按到第三行了,而第一行还有灯没亮,那么一定失败。
if(x>2&&check2(x)) return;
if(cnt>=6) return;
//x,y操作
work(x,y);
cnt++;
if(y<5) dfs(x,y+1);
else dfs(x+1,1);
//恢复现场
work(x,y);
cnt--;
}
int main()
{
int T;
cin>>T;
while(T--)
{
ans=10;
for(int i=1;i<=5;++i)
{
cin>>ch+1;
for(int j=1;j<=5;++j)
{
map[i][j]=ch[j]-'0';
}
}
cnt=0;
dfs(1,1);
if(ans>6) cout<<"-1"<<endl;
else cout<<ans<<endl;
}
return 0;
}