题意:
给一块n*m的地板,每块地板有黑白两种颜色,1是黑,0是白。如果翻动一块地板,那么包括它在内的上下左右五块地板都将翻转。问题是求最少翻转哪些地板能让所有地板都为白色。
首先对于每个砖块来说,翻两次和不翻是没有区别的,所以每个砖块最多翻一次。那么我们从上面第一行开始看,因为每一次对板子操作都会影响其周围周围的板子。所以,每次想要改变黑色板子(1)的时候,都要翻其下面的板子,如果一个板子的上、左、右及其本身确定,那么下面的也就确定。
如果第一行的板子确定了,那么以下的板子也就确定了,所以先枚举第一行的所有形式。如果所有板子都确定了,就应该开始判断最后一行是否还有黑色。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAX = 20; int num[MAX][MAX],t[MAX][MAX],ans[MAX][MAX]; int minn=0x3f3f3f3f; bool judge(int n,int m) { for(int i=1;i<=m;i++) if((num[n][i]+t[n][i]+t[n-1][i]+t[n][i-1]+t[n][i+1])&1) return false; return true; } void dfs(int n,int m,int k,int step) { if(step>minn) return; if(k>n) { if(judge(n,m)&&minn>step) { memcpy(ans,t,sizeof(t)); minn=step; } return; } int cnt=0; for(int i=1;i<=m;i++) { if((num[k-1][i]+t[k-2][i]+t[k-1][i]+t[k-1][i-1]+t[k-1][i+1])&1) { t[k][i]=1; cnt++; } else t[k][i]=0; } dfs(n,m,k+1,step+cnt); } void direction(int n,int m,int k,int step) { if(k>m) { dfs(n,m,2,step); return; } t[1][k]=0; direction(n,m,k+1,step); t[1][k]=1; direction(n,m,k+1,step+1); } int main(void) { int n,m; while(cin>>n>>m) { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>num[i][j]; direction(n,m,1,0); if(minn==0x3f3f3f3f) cout<<"IMPOSSIBLE"<<endl; else { for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cout<<ans[i][j]<<" "; cout<<endl; } } } return 0; }
“(num[k-1][i]+t[k-2][i]+t[k-1][i]+t[k-1][i-1]+t[k-1][i+1])&1”
这句话是求 t[k][i]上面的板子是不是黑色 别忘了(* ̄∇ ̄*)
拿这组数据说
3 3
1 0 0 它第一行共有7种形式,就是二进制的0~7。
1 1 0
0 0 1
这组数据的解是
1 0 1
0 0 1
0 0 0
当第一行确定之后,地板就变成了这样
0 0 1
0 1 1
0 0 1
当n=2,m=3时,它上面是1所以它需要翻转
(num[k-1][i]+t[k-2][i]+t[k-1][i]+t[k-1][i-1]+t[k-1][i+1])&1
=(0+0+1+0+0)&1=1 所以它需要翻转
这个题还是挺好的所以写个随笔没事自己看看。
浙公网安备 33010602011771号