题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2459
解题报告:题目的意思是,一个nXn 的矩阵,然后每个元素由0或1组成,然后现在要通过将矩阵中的某些0元素变为1来使矩阵的每一个元素的上下左右四个元素(如果存在的话)的值的和为偶数,现在问需要变动的最少的次数是多少?
因为题目的数据量n <= 15,其中一种想法是枚举矩阵的每个元素变还是不变,但是15X15=225,这样时间复杂度将是2^225次方,所以,这样不行。但是我们可以发现如果把第一行的元素都确定下来,那么下面的每一行都可以由上一行推出来,所以,解法就出来了,我们可以每次枚举第一行的元素,然后通过第一行的元素将后面的元素都推出来,这样的话时间复杂度将是2^15,很明显就可以通过测试数据了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 int add_x[4] = {-1,0,1,0}; 7 int add_y[4] = {0,1,0,-1}; 8 int matrix[20][20],temp[20][20]; 9 int changeto(int n,int m) //一开始傻了,把这个返回值指定为bool型 10 { 11 int f = 0,s = 0; 12 memset(temp,0,sizeof(temp)); 13 for(int i = 0;i < m;++i) 14 if(n & (1 << i)) 15 temp[0][i] = 1; 16 else temp[0][i] = 0; 17 for(int i = 0;i < m;++i) 18 { 19 if(temp[0][i] == 0 && matrix[0][i] == 1) 20 return -1; 21 else if(temp[0][i] == 1 && matrix[0][i] == 0) 22 s++; 23 } 24 return s; 25 } 26 27 int solve(int n) 28 { 29 int maxn = 1 << n,ans = 0x7fffffff; 30 for(int i = 0;i < maxn;++i) 31 { 32 int tt = changeto(i,n); 33 if(tt != -1) // 枚举第一行,然后其它行就可以由第一行推出 34 { 35 for(int j = 1;j < n;++j) 36 for(int k = 0;k < n;++k) 37 temp[j][k] = matrix[j][k]; 38 int t = 0; 39 for(int j = 0;j < n;++j) 40 for(int k = 0;k < n;++k) 41 { 42 int sum = 0; 43 for(int p = 0;p < 4;++p) //计算出该点的上下左右四个位置的和 44 { 45 int xx = j + add_x[p]; 46 int yy = k + add_y[p]; 47 if(xx >= 0 && xx < n && yy >= 0 && yy < n) 48 sum += temp[xx][yy]; 49 } 50 if(sum & 1) //如果四个位置的和为偶数则不用管,如果是奇数则... 51 { 52 if(j >= n - 1) //如果最后一行的出现奇数的话,没有办法了 53 goto loop; 54 if(temp[j+1][k] == 1) //如果下方的是1,不能把1变0,所以也没有办法 55 goto loop; 56 else //剩下的情况就是加起来的和是奇数,但可以将下面的那个数由0变1,其它位置的数一定是固定的 57 { 58 temp[j+1][k] = 1; 59 t++; 60 } 61 } 62 } 63 // if(t == 1 || tt == 1) 64 // { 65 // printf("i = %d ",i); 66 // for(int j = 0;j < n;++j) 67 // for(int k = 0;k < n;++k) 68 // printf(k == n-1? "%d ":"%d ",temp[j][k]); 69 // } 70 // printf("t = %d tt = %d ",t,tt); 71 ans = min(ans,t+tt); // 别忘记加上第一行变的 72 } 73 loop: ; 74 } 75 return ans > 225? -1:ans; 76 } 77 /*int slove(int k,int n) 78 { 79 int fir = changeto(k,n); 80 if(fir == -1) 81 return 10000; 82 for(int i = 1;i < n;++i) 83 84 for(int j = 0;j < n;++j) 85 temp[i][j] = matrix[i][j]; 86 int tot = 0; 87 for(int i = 0;i < n;++i) 88 for(int j = 0;j < n;++j) 89 { 90 int sum = 0; 91 for(int p = 0;p < 4;++p) 92 { 93 int xx = i + add_x[p]; 94 int yy = j + add_y[p]; 95 if(xx >= 0 && xx < n && yy >= 0 && yy < n) 96 sum += temp[xx][yy]; 97 } 98 if(sum & 1) 99 { 100 if(i >= n - 1 || temp[i+1][j] == 1) 101 return -1; 102 if(temp[i+1][j] == 0) 103 { 104 temp[i+1][j] = 1; 105 tot++; 106 } 107 } 108 } 109 return tot+fir; 110 }*/ 111 int main() 112 { 113 // freopen("in.txt","r",stdin); 114 int n,T,kase = 1; 115 scanf("%d",&T); 116 while(T--) 117 { 118 scanf("%d",&n); 119 for(int i = 0;i < n;++i) 120 for(int j = 0;j < n;++j) 121 scanf("%d",&matrix[i][j]); 122 printf("Case %d: %d ",kase++,solve(n)); 123 } 124 return 0; 125 }