kb-01-d<poj3279>--深搜变种,二进制优化;
poj--3279
题意:
给n*m的矩阵,0 1组成,每次翻转一个格子可以将上下左右的五个节点翻转,求,把所有的格子翻转成0;输出每个个字的翻转次数;最少字数;
做法:
从上到下,第一行翻转的情况确定的话就全确定了;因此只要枚举第一行的翻转情况就可以了;
第一行翻转0次或1次;所以可以用二进制化,不用dfs了;具体看代码实现;
对于每一种第一行看需要翻转的次数是否是最小的;
代码如此:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #define inf 0x3f3f3f3f 6 using namespace std; 7 int n,m,ans; 8 int a[20][20],vis[20][20]={0},t[20][20]={0},p[5][2]={0,0,0,1,0,-1,1,0,-1,0},an[20][20]={0}; 9 bool s[20]; //vis数组用来记录主动翻转的情况;t数组用来记录一共翻转的次数;an数组用来记录最终结果; 10 int solve() //根据第一行的情况确定剩余所有行的情况; 11 { 12 for(int i=0;i<m;i++) 13 { 14 if(vis[0][i]==1) 15 { 16 t[0][i]++; 17 if(n>1) 18 t[1][i]++; 19 if(i<m-1) 20 t[0][i+1]++; 21 if(i>0) 22 t[0][i-1]++; 23 } 24 } 25 for(int i=1;i<n;i++) 26 { 27 for(int j=0;j<m;j++) 28 { 29 if(t[i-1][j]%2!=a[i-1][j]) 30 { 31 vis[i][j]=1; 32 for(int z=0;z<5;z++) 33 { 34 int x=i+p[z][0],y=j+p[z][1]; 35 t[x][y]++; 36 } 37 } 38 } 39 } 40 for(int i=0;i<n;i++) 41 { 42 for(int j=0;j<m;j++) 43 { 44 if(t[i][j]%2!=a[i][j]) 45 return 0; 46 } 47 } 48 return 1; 49 } 50 int main() 51 { 52 while(cin>>n>>m) 53 { 54 memset(a,0,sizeof(a)); 55 memset(vis,0,sizeof(vis)); 56 memset(t,0,sizeof(t)); 57 ans=inf; 58 for(int i=0;i<n;i++) 59 { 60 for(int j=0;j<m;j++) 61 { 62 scanf("%d",&a[i][j]); 63 } 64 } 65 for(int i=0;i<pow(2.0,m);i++) 66 { 67 memset(vis,0,sizeof(vis)); 68 for(int j=m-1;j>=0;j--) 69 { 70 s[j]=i&(1<<j); 71 vis[0][j]=s[j]; 72 } 73 memset(t,0,sizeof(t)); 74 int temp=solve(),cou=0; 75 if(temp==1) 76 { 77 for(int i=0;i<n;i++) 78 { 79 for(int j=m-1;j>=0;j--) 80 { 81 if(vis[i][j]==1) 82 cou++; 83 } 84 } 85 if(cou<ans) 86 { 87 ans=cou; 88 for(int i=0;i<n;i++) 89 { 90 for(int j=m-1;j>=0;j--) 91 an[i][j]=vis[i][j]; 92 } 93 94 } 95 } 96 } 97 if(ans!=inf) 98 for(int i=0;i<n;i++) 99 { 100 for(int j=0;j<m;j++) 101 { 102 if(j!=0) 103 printf(" "); 104 printf("%d",an[i][j]); 105 } 106 printf("\n"); 107 } 108 else 109 printf("IMPOSSIBLE\n"); 110 } 111 112 return 0; 113 }