POJ 1681 Painter's Problem (高斯消元 枚举自由变元求最小的步数)
题意:
一个n*n 的木板 ,每个格子 都 可以 染成 白色和黄色,( 一旦我们对也个格子染色 ,他的上下左右 都将改变颜色);
给定一个初始状态 , 求将 所有的 格子 染成黄色 最少需要染几次? 若 不能 染成 输出 inf。
分析:
和1222差不多,唯一的区别是这个题还要求 最短的步数,其实只需要枚举一下最后的x[][]是否为1,即是否需要按下,
由于只有无解或者解唯一,因为按的顺序是没有影响的,所以只要是有解一定唯一,而且最短的情况是每个格子只按一次,
因为按两次以后就变为原来的状态了。
这个是最严谨的这个题的AC代码,因为我做1753的时候用原来的方法错了,看了Kuangbin的博客,知道原来的方法不对,貌似只有一个解和无解的时候才会对。
但是这个是对的:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #define LL __int64 8 const int maxn = 300+10; 9 const int INF = 1<<28; 10 using namespace std; 11 int equ, var, fn; 12 int a[maxn][maxn], x[maxn]; 13 int free_x[maxn]; 14 int gcd(int a, int b) 15 { 16 return b==0?a:gcd(b, a%b); 17 } 18 int lcm(int a, int b) 19 { 20 return a*b/gcd(a, b); 21 } 22 int Gauss() 23 { 24 int x_mo; 25 x_mo = 2; 26 int i, j, k, max_r, col; 27 int ta, tb, LCM, fx_num = 0; 28 col = 0; 29 30 for(k = 0; k<equ && col<var; k++, col++) 31 { 32 max_r = k; 33 for(i = k+1; i < equ; i++) 34 if(abs(a[i][col])>abs(a[max_r][col])) 35 max_r = i; 36 37 if(max_r != k) 38 for(j = k; j < var+1; j++) 39 swap(a[k][j], a[max_r][j]); 40 41 if(a[k][col]==0) 42 { 43 free_x[fx_num++] = col; //求自由变元所在的列 44 k--; 45 continue; 46 } 47 for(i = k+1; i < equ; i++) 48 { 49 if(a[i][col] != 0) 50 { 51 LCM = lcm(abs(a[i][col]), abs(a[k][col])); 52 ta = LCM/abs(a[i][col]); 53 tb= LCM/abs(a[k][col]); 54 if(a[i][col]*a[k][col] < 0) tb = -tb; 55 56 for(j = col; j < var+1; j++) 57 a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo; 58 } 59 } 60 } 61 for(i = k; i < equ; i++) 62 if(a[i][col] != 0) 63 return -1; 64 65 //以下为模2情况下的,枚举变元的方法。 66 int stat=1<<(var-k);//自由变元有 var-k 个 67 int res=INF; 68 for(i=0;i<stat;i++)//枚举所有变元 69 { 70 int cnt=0; 71 int index=i; 72 for(j=0;j<var-k;j++) 73 { 74 x[free_x[j]]=(index&1); 75 if(x[free_x[j]]) cnt++; 76 index>>=1; 77 } 78 for(j=k-1;j>=0;j--) 79 { 80 int tmp=a[j][var]; 81 for(int l=j+1;l<var;l++) 82 if(a[j][l]) tmp^=x[l]; 83 x[j]=tmp; 84 if(x[j])cnt++; 85 } 86 if(cnt<res)res=cnt; 87 } 88 return res; 89 } 90 91 int main() 92 { 93 int t, i, j, n, tmp; 94 char s[maxn]; 95 scanf("%d", &t); 96 while(t--) 97 { 98 memset(a, 0, sizeof(a)); 99 memset(x, 0, sizeof(x)); 100 scanf("%d", &n); 101 equ = n*n; 102 var = n*n; 103 for(i = 0; i < n; i++) 104 { 105 getchar(); 106 scanf("%s", s); 107 for(j = 0; j < n; j++) 108 { 109 if(s[j]=='y') a[i*n+j][n*n] = 0; //y时为0 110 else a[i*n+j][n*n] = 1; 111 } 112 } 113 for(i = 0; i < n; i++) 114 for(j = 0; j < n; j++) 115 { 116 tmp = i*n+j; 117 a[tmp][tmp] = 1; 118 if(j<=n-2) 119 a[tmp+1][tmp] = 1; 120 if(j>=1) 121 a[tmp-1][tmp] = 1; 122 if(tmp+n<n*n) 123 a[tmp+n][tmp] = 1; 124 if(tmp-n>=0) 125 a[tmp-n][tmp] = 1; 126 } 127 fn = Gauss(); 128 if(fn==-1) 129 printf("inf\n"); 130 else 131 printf("%d\n", fn); 132 } 133 return 0; 134 }
这个AC代码是我按照模板改的,但是在多解的情况下不对:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #define LL __int64 8 const int maxn = 300+10; 9 using namespace std; 10 int equ, var, fn; 11 int a[maxn][maxn], x[maxn]; 12 int gcd(int a, int b) 13 { 14 return b==0?a:gcd(b, a%b); 15 } 16 int lcm(int a, int b) 17 { 18 return a*b/gcd(a, b); 19 } 20 int Gauss() 21 { 22 int x_mo; 23 x_mo = 2; 24 int i, j, k, max_r, col; 25 int ta, tb, LCM, tmp; 26 col = 0; 27 28 for(k = 0; k<equ && col<var; k++, col++) 29 { 30 max_r = k; 31 for(i = k+1; i < equ; i++) 32 if(abs(a[i][col])>abs(a[max_r][col])) 33 max_r = i; 34 35 if(max_r != k) 36 for(j = k; j < var+1; j++) 37 swap(a[k][j], a[max_r][j]); 38 39 if(a[k][col]==0) 40 { 41 k--; 42 continue; 43 } 44 for(i = k+1; i < equ; i++) 45 { 46 if(a[i][col] != 0) 47 { 48 LCM = lcm(abs(a[i][col]), abs(a[k][col])); 49 ta = LCM/abs(a[i][col]); 50 tb= LCM/abs(a[k][col]); 51 if(a[i][col]*a[k][col] < 0) tb = -tb; 52 53 for(j = col; j < var+1; j++) 54 a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo; 55 } 56 } 57 } 58 for(i = k; i < equ; i++) 59 if(a[i][col] != 0) 60 return -1; 61 62 for(i = var-1; i >= 0; i--) 63 { 64 tmp = a[i][var]; 65 for(j = i+1; j < var; j++) 66 if(a[i][j] != 0) 67 tmp = ((tmp-a[i][j]*x[j])%x_mo+x_mo)%x_mo; 68 if(a[i][i]==0) //注意这a[i][i]可能为0, 我改为这样就对了。 69 x[i] = 0; 70 else 71 { 72 while(tmp%a[i][i]!=0) tmp += x_mo; 73 x[i] = (tmp/a[i][i])%x_mo; 74 } 75 } 76 return 0; 77 } 78 79 int main() 80 { 81 int t, i, j, n, ans, tmp; 82 char s[maxn]; 83 scanf("%d", &t); 84 while(t--) 85 { 86 memset(a, 0, sizeof(a)); 87 memset(x, 0, sizeof(x)); 88 scanf("%d", &n); 89 equ = n*n; 90 var = n*n; 91 for(i = 0; i < n; i++) 92 { 93 getchar(); 94 scanf("%s", s); 95 for(j = 0; j < n; j++) 96 { 97 if(s[j]=='y') a[i*n+j][n*n] = 0; //y时为0 98 else a[i*n+j][n*n] = 1; 99 } 100 } 101 for(i = 0; i < n; i++) 102 for(j = 0; j < n; j++) 103 { 104 tmp = i*n+j; 105 a[tmp][tmp] = 1; 106 if(j<=n-2) 107 a[tmp+1][tmp] = 1; 108 if(j>=1) 109 a[tmp-1][tmp] = 1; 110 if(tmp+n<n*n) 111 a[tmp+n][tmp] = 1; 112 if(tmp-n>=0) 113 a[tmp-n][tmp] = 1; 114 } 115 fn = Gauss(); 116 if(fn==-1) 117 printf("inf\n"); 118 else 119 { 120 ans = 0; 121 for(i = 0; i < n*n; i++) 122 if(x[i]==1) //枚举解为1,就是需要将原来的翻转的。 123 ans ++; 124 printf("%d\n", ans); 125 } 126 } 127 return 0; 128 }
这个AC代码的模板用的是别人的对二取模的模板,用的是 ^异或,不会出现除0的情况。在多解的情况下也不对。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #define LL __int64 8 const int maxn = 300+10; 9 using namespace std; 10 int equ, var, fn; 11 int a[maxn][maxn], x[maxn]; 12 int gcd(int a, int b) 13 { 14 return b==0?a:gcd(b, a%b); 15 } 16 int lcm(int a, int b) 17 { 18 return a*b/gcd(a, b); 19 } 20 int Gauss() 21 { 22 int i,j,k; 23 int max_r; 24 int col; 25 int temp; 26 27 int free_x_num; 28 int free_index; 29 30 col=0; 31 for(k=0;k<equ&&col<var;k++,col++) 32 { 33 max_r=k; 34 for(i=k+1;i<equ;i++) 35 { 36 if(abs(a[i][col])>abs(a[max_r][col]))max_r=i; 37 } 38 if(max_r!=k) 39 { 40 for(j=col;j<var+1;j++)swap(a[k][j],a[max_r][j]); 41 } 42 if(a[k][col]==0) 43 { 44 k--; 45 continue; 46 } 47 for(i=k+1;i<equ;i++) 48 { 49 if(a[i][col]!=0) 50 { 51 for(j=col;j<var+1;j++) 52 a[i][j]^=a[k][j]; 53 } 54 } 55 } 56 for(i=k;i<equ;i++) 57 { 58 if(a[i][col]!=0)return -1; 59 } 60 for(i=var-1;i>=0;i--) 61 { 62 x[i]=a[i][var]; 63 for(j=i+1;j<var;j++) 64 x[i]^=(a[i][j]&&x[j]); 65 } 66 return 0; 67 } 68 69 int main() 70 { 71 int t, i, j, n, ans, tmp; 72 char s[maxn]; 73 scanf("%d", &t); 74 while(t--) 75 { 76 memset(a, 0, sizeof(a)); 77 memset(x, 0, sizeof(x)); 78 scanf("%d", &n); 79 equ = n*n; 80 var = n*n; 81 for(i = 0; i < n; i++) 82 { 83 getchar(); 84 scanf("%s", s); 85 for(j = 0; j < n; j++) 86 { 87 if(s[j]=='y') a[i*n+j][n*n] = 0; 88 else a[i*n+j][n*n] = 1; 89 } 90 } 91 for(i = 0; i < n; i++) 92 for(j = 0; j < n; j++) 93 { 94 tmp = i*n+j; 95 a[tmp][tmp] = 1; 96 if(j<=n-2) 97 a[tmp+1][tmp] = 1; 98 if(j>=1) 99 a[tmp-1][tmp] = 1; 100 if(tmp+n<n*n) 101 a[tmp+n][tmp] = 1; 102 if(tmp-n>=0) 103 a[tmp-n][tmp] = 1; 104 } 105 fn = Gauss(); 106 if(fn==-1) 107 printf("inf\n"); 108 else 109 { 110 ans = 0; 111 for(i = 0; i < n*n; i++) 112 if(x[i]==1) 113 ans ++; 114 printf("%d\n", ans); 115 } 116 } 117 return 0; 118 }