这个题可以用高斯消元来解,那就是水题
不过有很多有意思的解法,例举一二
1贪心:
从左到右枚举一边(每个硬币翻还是不翻仅由其前面的硬币的状态决定)
但是有这种情况:
110000000...(省略n多个0)
可证,反而是从第一个开始翻就比较好
这样就从右再向左枚举一边
两次枚举,得结果
也可这样看,枚举第一个硬币翻还是不翻
代码一:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
int num[40]={0},nc[40]={0};
int deal(int a){
if(a==0)return 1;
if(a==1)return 0;
}
int Min(int a,int b){
if(a<b)return a;
return b;
}
int main(){
int tmp1,tmp2;
int cnt=200;
for(int i=1;i<=20;i++){
scanf("%d",&num[i]);
nc[i]=num[i];
}
tmp1=0;// 1fanzhuan
//num[1]=!num[1];
for(int i=1;i<=20;i++){
if(num[i-1]){
num[i-1]=0;
num[i]=deal(num[i]);
num[i+1]=deal(num[i+1]);
tmp1++;
}
}
tmp2=0;//1bufanzhuan
//nc[1]=nc[1];
for(int i=19;i>=0;i--){
if(nc[i+1]){
nc[i+1]=0;
nc[i]=deal(nc[i]);
nc[i-1]=deal(nc[i-1]);
tmp2++;
}
}
cnt=Min(tmp1,tmp2);
printf("%d\n",cnt);
}
代码二:
#include <iostream>
using namespace std;
int bowl[25]={0},flip[25]={0};
int main()
{
int i,cnt=100,tmp;
for (i=1;i<21;i++) cin >> bowl[i];
flip[1] = tmp = 1; //翻第一个
for (i=2;i<21;i++)
if ( flip[i] = (flip[i-2]^flip[i-1]^bowl[i-1]) ) tmp++;
if ( tmp<cnt && (flip[19]^flip[20]^bowl[20])==0 ) cnt = tmp;
flip[1] = tmp = 0; //不翻第一个
for (i=2;i<21;i++)
if ( flip[i] = (flip[i-2]^flip[i-1]^bowl[i-1]) ) tmp++;
if ( tmp<cnt && (flip[19]^flip[20]^bowl[20])==0 ) cnt = tmp;
cout << cnt << endl;
return 0;
}
2暴搜:
详见代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int num[27],step,flag;
int range()
{
int i;
for(i=0;i<20;i++)
if(num[i]==1)
return 0;
return 1;
}
void turn(int i)
{
num[i]=!num[i];
if(i>0)
num[i-1]=!num[i-1];
if(i<19)num[i+1]=!num[i+1];
}
void DFS(int i,int dp)
{
if(step==dp){
flag=range();//flag=1 fail
return;
}
if(i>=20||flag)return;
turn(i);
DFS(i+1,dp+1);//i zhuan
turn(i);
DFS(i+1,dp);//i buzhuan
}
int main()
{
int i;
for(i=0;i<20;i++)
scanf("%d",&num[i]);
for(step=0;step<20;step++)
{
flag=0;
DFS(0,0);
if(flag)break;
}
printf("%d\n",step);
return 0;
}