题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1092
题意:给出一个n*m的格子,每个格子是0或者1。每次翻转格子(i,j)的状态,周围8个格子的状态都要翻转。求最少的翻转次数使得所有格子均为1.
思路:枚举每一行的翻转状态,f[i][j][k]表示第i行,上一行的翻转状态为j,当前行没有翻转时上一行的状态为k的最小值。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int INF=1000000000; 7 int C,num=0; 8 int n,m,f[10][300][300],a[15]; 9 char s[15][15]; 10 int cnt[300]; 11 12 void init() 13 { 14 int i,j; 15 for(i=0;i<(1<<8);i++) 16 { 17 cnt[i]=0; 18 for(j=0;j<8;j++) if(i&(1<<j)) cnt[i]++; 19 } 20 } 21 22 23 24 inline int change(int st,int p) 25 { 26 int i,j; 27 for(i=0;i<m;i++) if(p&(1<<i)) 28 { 29 for(j=-1;j<=1;j++) if(i+j>=0&&i+j<m) 30 { 31 if(st&(1<<(i+j))) st=st^(1<<(i+j)); 32 else st|=(1<<i+j); 33 } 34 } 35 return st; 36 } 37 38 int DFS(int dep,int pre,int st) 39 { 40 if(dep==n+1) 41 { 42 if(st==(1<<m)-1) return 0; 43 return INF; 44 } 45 int &ans=f[dep][pre][st]; 46 if(ans!=-1) return ans; 47 ans=INF; 48 int i,j,st0,temp,p; 49 p=change(a[dep],pre); 50 for(i=0;i<(1<<m);i++) if(change(st,i)==(1<<m)-1) 51 { 52 temp=cnt[i]; 53 st0=change(p,i); 54 temp+=DFS(dep+1,i,st0); 55 if(temp<ans) ans=temp; 56 } 57 return ans; 58 } 59 60 int main() 61 { 62 init(); 63 for(scanf("%d",&C);C--;) 64 { 65 scanf("%d%d",&n,&m); 66 int i,j; 67 for(i=1;i<=n;i++) 68 { 69 scanf("%s",s[i]); 70 a[i]=0; 71 for(j=0;j<m;j++) a[i]=(a[i]<<1)+(s[i][j]=='*'); 72 } 73 memset(f,-1,sizeof(f)); 74 int ans=INF,temp,st; 75 for(i=0;i<(1<<m);i++) 76 { 77 temp=cnt[i]; 78 st=change(a[1],i); 79 if(f[1][0][st]!=-1) 80 { 81 temp+=f[1][0][st]; 82 } 83 else 84 { 85 f[1][0][st]=DFS(2,i,st); 86 temp+=f[1][0][st]; 87 } 88 if(temp<ans) ans=temp; 89 } 90 printf("Case %d: ",++num); 91 if(ans==INF) puts("impossible"); 92 else printf("%d\n",ans); 93 } 94 return 0; 95 }