题意:
给出棋盘,问最少按几步,按那几个,可以把所有的格子都变为0状态,并且输出
第一次写一道题用了两个晚上。网上的代码实在是太难看了。代码里有详细注释。
大体思路:
这个格子翻不翻取决与上面的格子,而上面的格子又受到之前的影响,个人感觉有些动态规划的意思。
#include<stdio.h>
#include<string.h>
#include <iostream>
#define inf 99999999
using namespace std;;
int mp[20][20];
int ans[20][20];
int fir[20][20];
int row,col;
int result;
int color(int x ,int y) //访问某一个格子的上面一个
{
int next[4][2]={0,1,0,-1,0,0,-1,0}; //上面一个格子是否需要改变取决与:
// 上面的上面,上面左面右面,以及之前棋盘的颜色。
int sum=mp[x][y];
for(int i=0;i<4;i++)
{
int sx=x+next[i][0];
int sy=y+next[i][1];
if(sx<1||sy<1||sx>row||sy>col)
continue;
sum+=fir[sx][sy];
}
if(sum&1)
return 1;
else
return 0;
}
void Prin()
{
for(int i=1;i<=row;i++)
{
printf("%d",ans[i][1]);
for(int j=2;j<=col;j++)
printf(" %d",ans[i][j]);
cout<<endl;
}
}
int main()
{
scanf("%d%d",&row,&col);
result=inf;
for(int i=1;i<=row;i++)
{
for(int j=1;j<=col;j++)
scanf("%d",&mp[i][j]);
}
//cout<<"--------"<<endl;
for(int i=1;i<= (1<<col) ;i++) //注意 是1<<col 不是col<<1 ,一个是枚举二进制,一个是col*2
{
int sum=0;
memset(fir,0,sizeof(fir));
for(int j=1;j<=col;j++)
{
fir[1][j]= ((i-1)>>(j-1))&1; //枚举某次的二进制 i / i-1都行 但是必须是j-1
if(fir[1][j]!=mp[1][j]) //如果不等第一行原来的值,则表明按了一下+1
sum++;
}
//可以试着打出来。是一个枚举二进制
/* for(int j=1;j<=col;j++)
{
printf("%d ",fir[1][j]);
}
cout<<endl;*/
for(int i=2;i<=row;i++)//对于第二行开始扫描,如果如果与按,并且
for(int j=1;j<=col;j++)
{
if(color(i-1,j)) //找到他的上一个格子,访问是否按下去
{ //改变状态
if(fir[i][j])
fir[i][j]=0;
else
fir[i][j]=1;
sum++;
}
}
int flag=1;
for(int i=1;i<=col;i++)
{
if(color(row,i))
{
flag=0;
break;
}
}
if(flag&&sum<result) //如果步骤少,储存临时结果
{
for(int i=1;i<=row;i++)
for(int j=1;j<=col;j++)
ans[i][j]=fir[i][j];
result=sum;
}
}
if(result!=inf)
Prin();
else
printf("IMPOSSIBLE\n");
}
#include<stdio.h>
#include<string.h>
#include <iostream>
#define inf 99999999
using namespace std;;
int mp[20][20];
int ans[20][20];
int fir[20][20];
int row,col;
int result;
int color(int x ,int y) //访问某一个格子的上面一个
{
int next[4][2]={0,1,0,-1,0,0,-1,0}; //上面一个格子是否需要改变取决与:
// 上面的上面,上面左面右面,以及之前棋盘的颜色。
int sum=mp[x][y];
for(int i=0;i<4;i++)
{
int sx=x+next[i][0];
int sy=y+next[i][1];
if(sx<1||sy<1||sx>row||sy>col)
continue;
sum+=fir[sx][sy];
}
if(sum&1)
return 1;
else
return 0;
}
void Prin()
{
for(int i=1;i<=row;i++)
{
printf("%d",ans[i][1]);
for(int j=2;j<=col;j++)
printf(" %d",ans[i][j]);
cout<<endl;
}
}
int main()
{
scanf("%d%d",&row,&col);
result=inf;
for(int i=1;i<=row;i++)
{
for(int j=1;j<=col;j++)
scanf("%d",&mp[i][j]);
}
//cout<<"--------"<<endl;
for(int i=1;i<= (1<<col) ;i++) //注意 是1<<col 不是col<<1 ,一个是枚举二进制,一个是col*2
{
int sum=0;
memset(fir,0,sizeof(fir));
for(int j=1;j<=col;j++)
{
fir[1][j]= ((i-1)>>(j-1))&1; //枚举某次的二进制 i / i-1都行 但是必须是j-1
if(fir[1][j]!=mp[1][j]) //如果不等第一行原来的值,则表明按了一下+1
sum++;
}
//可以试着打出来。是一个枚举二进制
/* for(int j=1;j<=col;j++)
{
printf("%d ",fir[1][j]);
}
cout<<endl;*/
for(int i=2;i<=row;i++)//对于第二行开始扫描,如果如果与按,并且
for(int j=1;j<=col;j++)
{
if(color(i-1,j)) //找到他的上一个格子,访问是否按下去
{ //改变状态
if(fir[i][j])
fir[i][j]=0;
else
fir[i][j]=1;
sum++;
}
}
int flag=1;
for(int i=1;i<=col;i++)
{
if(color(row,i))
{
flag=0;
break;
}
}
if(flag&&sum<result) //如果步骤少,储存临时结果
{
for(int i=1;i<=row;i++)
for(int j=1;j<=col;j++)
ans[i][j]=fir[i][j];
result=sum;
}
}
if(result!=inf)
Prin();
else
printf("IMPOSSIBLE\n");
}