[Usaco2007 Open]Fliptile 翻格子游戏
题目描述
Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which they manipulate an M x N grid (1 <= M <= 15; 1 <= N <= 15) of square tiles, each of which is colored black on one side and white on the other side. As one would guess, when a single white tile is flipped, it changes to black; when a single black tile is flipped, it changes to white. The cows are rewarded when they flip the tiles so that each tile has the white side face up. However, the cows have rather large hooves and when they try to flip a certain tile, they also flip all the adjacent tiles (tiles that share a full edge with the flipped tile). Since the flips are tiring, the cows want to minimize the number of flips they have to make. Help the cows determine the minimum number of flips required, and the locations to flip to achieve that minimum. If there are multiple ways to achieve the task with the minimum amount of flips, return the one with the least lexicographical ordering in the output when considered as a string. If the task is impossible, print one line with the word "IMPOSSIBLE".
输入
* Line 1: Two space-separated integers: M and N
* Lines 2..M+1: Line i+1 describes the colors (left to right) of row i of the grid with N space-separated integers which are 1 for black and 0 for white
输出
* Lines 1..M: Each line contains N space-separated integers, each specifying how many times to flip that particular location.
样例输入
4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
样例输出
0 0 0 0 1 0 0 1 1 0 0 1 0 0 0 0 OUTPUT DETAILS: After flipping at row 2 column 1, the board will look like: 0 0 0 1 1 0 1 0 1 1 1 0 1 0 0 1 After flipping at row 2 column 4, the board will look like: 0 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 After flipping at row 3 column 1, the board will look like: 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 1 After flipping at row 3 column 4, the board will look like: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Another solution might be: 0 1 1 0 0 0 0 0 0 0 0 0 0 1 1 0 but this solution is lexicographically higher than the solution above.
solution:
这题上来大暴搜,搜到无能为力QAQ,5*5的方格就跳不出来了,然后我们再想,先不管是否合法,只要第一行状态确定,下面的状态其实就可以由上一行退出来,1代表这点翻,0代表不翻,只要一个点状态和它四周加和再加上原来的矩阵的中的黑色或白色所代表的数字的和为偶数,则当前点的最终颜色为白色。
而且数据范围很小,一看就是状压dp,先枚举第一行状态,最后判断是否合法且为最优解即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,m,mx; 7 int singl[17][17],state[2],change_num[17][17]; 8 void change() { 9 memset(change_num,0,sizeof(change_num)); 10 for(int i=1; i<=n; i++) { 11 if((1<<(n-i))&state[1]) { 12 change_num[1][i]=1; 13 } 14 } 15 } 16 int sum,ans=0x7ffffff; 17 bool check(int a[][17]) { 18 int s[17][17]; 19 for(int i=1; i<=m; i++) { 20 for(int j=1; j<=n; j++) { 21 s[i][j]=singl[i][j]; 22 } 23 } 24 for(int i=1; i<=m; i++) { 25 for(int j=1; j<=n; j++) { 26 if(a[i][j]) { 27 s[i-1][j]^=1; 28 s[i+1][j]^=1; 29 s[i][j-1]^=1; 30 s[i][j+1]^=1; 31 s[i][j]^=1; 32 } 33 } 34 } 35 for(int i=1; i<=m; i++) { 36 for(int j=1; j<=n; j++) { 37 if(s[i][j]) { 38 return false; 39 } 40 } 41 } 42 return true; 43 } 44 45 void tra(int x) { 46 state[1]=x; 47 change(); 48 for(int i=1; i<m; i++) { 49 for(int j=1; j<=n; j++) { 50 if(j==1) { 51 int ji=(change_num[i-1][j]+singl[i][j]+change_num[i][j+1])&1; 52 if(ji&&change_num[i][j]) { 53 change_num[i+1][j]=0; 54 } 55 if(ji&&!change_num[i][j]) { 56 change_num[i+1][j]=1; 57 } 58 if(!ji&&change_num[i][j]) { 59 change_num[i+1][j]=1; 60 } 61 if(!ji&&!change_num[i][j]) { 62 change_num[i+1][j]=0; 63 } 64 continue; 65 } 66 if(j==n) { 67 int ji=(change_num[i-1][j]+singl[i][j]+change_num[i][j-1])&1; 68 if(ji&&change_num[i][j]) { 69 change_num[i+1][j]=0; 70 } 71 if(ji&&!change_num[i][j]) { 72 change_num[i+1][j]=1; 73 } 74 if(!ji&&change_num[i][j]) { 75 change_num[i+1][j]=1; 76 } 77 if(!ji&&!change_num[i][j]) { 78 change_num[i+1][j]=0; 79 } 80 continue; 81 } 82 int ji=(change_num[i-1][j]+singl[i][j]+change_num[i][j-1]+change_num[i][j+1])&1; 83 if(ji&&change_num[i][j]) { 84 change_num[i+1][j]=0; 85 } 86 if(ji&&!change_num[i][j]) { 87 change_num[i+1][j]=1; 88 } 89 if(!ji&&change_num[i][j]) { 90 change_num[i+1][j]=1; 91 } 92 if(!ji&&!change_num[i][j]) { 93 change_num[i+1][j]=0; 94 } 95 } 96 } 97 } 98 int cun[17][17]; 99 bool pp() { 100 for(int i=1; i<=m; i++) { 101 for(int j=1; j<=n; j++) { 102 if(cun[i][j]<change_num[i][j]) { 103 return false; 104 } 105 if(cun[i][j]>change_num[i][j]) { 106 return true; 107 } 108 } 109 } 110 return false; 111 } 112 int main() { 113 memset(cun,0x3f,sizeof(cun)); 114 scanf("%d%d",&m,&n); 115 for(int i=1; i<=m; i++) { 116 for(int j=1; j<=n; j++) { 117 scanf("%d",&singl[i][j]); 118 } 119 } 120 mx=(1<<n); 121 bool pd=0; 122 for(int i=0; i<mx; i++) { 123 tra(i); 124 if(check(change_num)) { 125 sum=0; 126 pd=1; 127 for(int i=1; i<=m; i++) { 128 for(int j=1; j<=n; j++) { 129 if(change_num[i][j]) { 130 ++sum; 131 } 132 } 133 } 134 if(sum==ans&&pp()) { 135 for(int i=1; i<=m; i++) { 136 for(int j=1; j<=n; j++) { 137 cun[i][j]=change_num[i][j]; 138 } 139 } 140 } 141 if(sum<ans) { 142 ans=sum; 143 for(int i=1; i<=m; i++) { 144 for(int j=1; j<=n; j++) { 145 cun[i][j]=change_num[i][j]; 146 } 147 } 148 } 149 } 150 } 151 if(!pd) { 152 printf("IMPOSSIBLE"); 153 } else { 154 for(int i=1; i<=m; i++) { 155 for(int j=1; j<=n; j++) { 156 printf("%d ",cun[i][j]); 157 } 158 printf("\n"); 159 } 160 } 161 return 0; 162 }