题目链接:http://poj.org/problem?id=2965
题解:自己想到的方法是枚举搜索,结果用bfs和dfs写都超时了。网上拿别人的代码试一下只是刚好不超时的,如果自己的代码在某些方面不够优化,那超时很正常。看来这题用dfs和bfs都不是好办法。 然后又看到比较厉害的技巧:“可知翻偶数次等于没翻,即没有翻的必要,翻奇数次的结果与翻一次的结果一样“”。有了这个重要结论,那么可以具体操作了:设一个二维数组以记录每个的翻转次数。对于每个‘+’,都翻转其所在的行列(注意‘+’只翻一次),然后更新翻转次数。最后统计翻转次数为奇数的,即为实际需要翻转的。(为什么我没想到这种方法。需要仔细体会这种思维)
代码如下:
1 #include<stdio.h>//poj2965 2 #include<string.h> 3 int main() 4 { 5 int a[5][5],sum; 6 char map[5][5];//map开一维已足够 7 memset(a,0,sizeof(a)); 8 for(int i = 0; i<4; i++) 9 { 10 scanf("%s",map[i]); 11 for(int j = 0; j<4; j++) 12 { 13 if(map[i][j]=='+') 14 { 15 a[i][j]--;//‘+’在下面的步骤中翻了两次,要减少一次 16 for(int k = 0; k<4; k++) 17 { 18 a[k][j]++; 19 a[i][k]++; 20 } 21 } 22 } 23 } 24 sum = 0; 25 for(int i = 0; i<4; i++) 26 for(int j = 0; j<4; j++) 27 { 28 if(a[i][j]%2) sum++; 29 } 30 printf("%d ",sum); 31 32 for(int i = 0; i<4; i++) 33 for(int j = 0; j<4; j++) 34 { 35 if(a[i][j]%2) 36 printf("%d %d ",i+1,j+1); 37 } 38 }
对了,附上自己wa了的dfs和bfs;
dfs:
1 #include<cstdio>//poj 2965dfs 超时未过 2 #include<cstring> 3 #define MIN(a,b) (a<b?a:b) 4 5 int a[20],ans[20]; 6 7 int get() 8 { 9 for(int i = 0; i<16; i++) 10 if(a[i]) return 0; 11 return 1; 12 } 13 14 void flip(int loc) 15 { 16 int x = loc/4, y = loc%4; 17 a[loc] = !a[loc]; 18 for(int k = 0; k<4; k++) 19 a[x*4+k] = !a[x*4+k]; 20 for(int k = 0; k<4; k++) 21 a[k*4+y] = !a[k*4+y]; 22 } 23 24 int dfs(int loc,int step,int tar) 25 { 26 if(loc>16) return 0; 27 28 if(step==tar && get()) 29 return 1; 30 31 else 32 { 33 flip(loc); 34 ans[step] = loc; 35 if(dfs(loc+1,step+1,tar)) return 1; 36 flip(loc); 37 38 if(dfs(loc+1,step,tar)) return 1; 39 40 } 41 return 0; 42 } 43 44 int main() 45 { 46 int t; 47 char s[10]; 48 49 memset(ans,-1,sizeof(ans)); 50 for(int i = 0; i<4; i++) 51 { 52 scanf("%s",s); 53 for(int j = 0; j<4; j++) 54 { 55 if(s[j]=='+') a[i*4+j] = 1; 56 else a[i*4+j] = 0; 57 } 58 } 59 int i; 60 for(i = 1; i<=16; i++) 61 { 62 if(dfs(0,0,i)) break; 63 } 64 printf("%d ",i); 65 for(int k = 0; k<i; k++) 66 { 67 if(ans[k]!=-1) 68 printf("%d %d ",ans[k]/4+1, ans[k]%4+1); 69 } 70 71 return 0; 72 }
bfs:(bfs的队列可能不够大,溢出。用stl的话又怎么记录路径呢?)
1 #include<cstdio>//poj 2965 bfs 未过 2 #include<cstring> 3 #include<queue> 4 5 using namespace std; 6 7 int ss,vis[65536],pre[65536]; 8 struct node 9 { 10 int status, step,loc; 11 }; 12 node q[65536]; 13 14 void calcul( node *next,int i) 15 { 16 if(next->status&(1<<i)) next->status -= (1<<i); 17 else next->status += (1<<i); 18 } 19 20 void turn (node *next,int i) 21 { 22 calcul(next,i); 23 int xi = i/4, yi = i%4; 24 for(int k = 0; k<4; k++) 25 calcul(next,xi*4+k); 26 for(int k = 0; k<4; k++) 27 calcul(next,k*4+yi); 28 } 29 30 int bfs() 31 { 32 int front = 0, rear = 1; 33 q[front].status = ss, q[front].step = 0; 34 vis[q[front].status] = 1; 35 if(q[front].status==0) 36 return front; 37 memset(vis,0,sizeof(vis)); 38 memset(pre,0,sizeof(pre)); 39 while(front<rear) 40 { 41 for(int i = 0; i<16; i++) 42 { 43 q[rear].status = q[front].status; 44 turn(&q[rear],i); 45 if(vis[q[rear].status]) continue; 46 47 q[rear].loc = i; 48 q[rear].step = q[front].step + 1; 49 pre[rear] = front; 50 vis[q[rear].status] = 1; 51 52 if(q[rear].status==0) return rear; 53 rear++; 54 } 55 front++; 56 } 57 return -1; 58 } 59 60 void pri_path(int rear) 61 { 62 if(q[rear].step>1) pri_path(pre[rear]); 63 printf("%d %d ",q[rear].loc/4+1, q[rear].loc%4+1); 64 } 65 66 int main() 67 { 68 int t; 69 char s[10]; 70 ss = 0; 71 72 for(int i = 0; i<4; i++) 73 { 74 scanf("%s",s); 75 for(int j = 0; j<4; j++) 76 { 77 if(s[j]=='+') ss += 1<<(i*4+j); 78 } 79 } 80 int rear = bfs(); 81 printf("%d ",q[rear].step); 82 83 pri_path(rear); 84 return 0; 85 }