http://poj.org/problem?id=1681
题意:
有一块只有黄白颜色的n*n的板子,每次刷一块格子时,上下左右都会改变颜色,求最少刷几次可以使得全部变成黄色。
思路:
这道题目也就是要处理自由变元,如果自由变元为0,那么刷法是唯一的,如果有多个自由变元,那么可以有多种刷法,需要枚举处理。
借鉴了kuangbin大神的高斯消元模板,写得真的是好。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<sstream> 6 #include<vector> 7 #include<stack> 8 #include<queue> 9 #include<cmath> 10 #include<map> 11 #include<set> 12 using namespace std; 13 typedef long long ll; 14 typedef pair<int,int> pll; 15 const int INF = 0x3f3f3f3f; 16 const int maxn = 400 + 5; 17 18 int n; 19 int equ,var; //equ个方程,var个变元 20 int x[maxn]; //解集 21 int a[maxn][maxn]; //矩阵 22 int free_x[maxn]; //存储自由变元 23 int free_num; //自由变元的个数 24 25 //返回值为-1表示无解,为0表示唯一解,否则返回自由变元个数 26 int Gauss() 27 { 28 int max_r,col,k; 29 free_num=0; 30 for(k=0,col=0; k<equ && col<var; k++,col++) 31 { 32 max_r=k; 33 for(int i=k+1;i<equ;i++) 34 { 35 if(abs(a[i][col])>abs(a[max_r][col])) 36 max_r=i; 37 } 38 if(a[max_r][col]==0) 39 { 40 k--; 41 free_x[free_num++]=col; //这个是自由变元; 42 continue; 43 } 44 if(max_r!=k) 45 { 46 for(int j=col; j<var+1; j++) 47 swap(a[k][j],a[max_r][j]); 48 } 49 for(int i=k+1;i<equ;i++) 50 { 51 if(a[i][col]!=0) 52 { 53 for(int j=col;j<var+1;j++) 54 a[i][j]^=a[k][j]; 55 } 56 } 57 } 58 for(int i=k;i<equ;i++) 59 if(a[i][col]!=0) return -1; //无解 60 if(k<var) return var-k; //有多解时返回自由变元个数 61 //唯一解,回代 62 for(int i=var-1; i>=0 ;i--) 63 { 64 x[i]=a[i][var]; 65 for(int j=i+1; j<var; j++) 66 x[i]^=(a[i][j] && x[j]); 67 } 68 return 0; 69 } 70 71 void print(int t) 72 { 73 if(t==-1) puts("inf"); 74 else if(t==0) 75 { 76 int ans=0; 77 for(int i=0;i<n*n;i++) ans+=x[i]; 78 printf("%d ",ans); 79 } 80 else 81 { 82 //枚举自由变元 83 int ans=INF; 84 for(int i=0;i<(1<<t);i++) 85 { 86 int cnt=0; 87 for(int j=0;j<t;j++) 88 { 89 if(i&(1<<j)) 90 { 91 x[free_x[j]]=1; 92 cnt++; 93 } 94 else x[free_x[j]]=0; 95 } 96 for(int j=var-t-1;j>=0;j--) 97 { 98 int idx; 99 for(idx=j; idx<var; idx++) 100 if(a[j][idx]) break; 101 x[idx]=a[j][var]; 102 for(int l=idx+1; l<var; l++) 103 if(a[j][l]) x[idx]^=x[l]; 104 cnt+=x[idx]; 105 } 106 ans=min(ans,cnt); 107 } 108 printf("%d ",ans); 109 } 110 } 111 112 int main() 113 { 114 //freopen("in.txt","r",stdin); 115 int T; 116 scanf("%d",&T); 117 while(T--) 118 { 119 scanf("%d",&n); 120 memset(a,0,sizeof(a)); 121 122 for(int i=0;i<n*n;i++) 123 { 124 a[i][i]=1; 125 if(i/n) a[i-n][i]=1; 126 if(i/n<n-1) a[i+n][i]=1; 127 if(i%n) a[i-1][i]=1; 128 if(i%n<n-1) a[i+1][i]=1; 129 } 130 131 char s[20]; 132 for(int i=0;i<n;i++) 133 { 134 scanf("%s",s); 135 for(int j=0;j<n;j++) 136 { 137 if(s[j]=='y') a[i*n+j][n*n]=0; 138 else a[i*n+j][n*n]=1; 139 } 140 } 141 142 memset(x,0,sizeof(x)); 143 equ=var=n*n; 144 print(Gauss()); 145 } 146 return 0; 147 }