POJ 1681 Painter's Problem (高斯消元 枚举自由变元求最小的步数)
2014-08-18 17:00
435 查看
题目链接
题意:
一个n*n 的木板 ,每个格子 都 可以 染成 白色和黄色,( 一旦我们对也个格子染色 ,他的上下左右 都将改变颜色);
给定一个初始状态 , 求将 所有的 格子 染成黄色 最少需要染几次? 若 不能 染成 输出 inf。
分析:
和1222差不多,唯一的区别是这个题还要求 最短的步数,其实只需要枚举一下最后的x[][]是否为1,即是否需要按下,
由于只有无解或者解唯一,因为按的顺序是没有影响的,所以只要是有解一定唯一,而且最短的情况是每个格子只按一次,
因为按两次以后就变为原来的状态了。
这个是最严谨的这个题的AC代码,因为我做1753的时候用原来的方法错了,看了Kuangbin的博客,知道原来的方法不对,貌似只有一个解和无解的时候才会对。
但是这个是对的:
这个AC代码是我按照模板改的,但是在多解的情况下不对:
这个AC代码的模板用的是别人的对二取模的模板,用的是 ^异或,不会出现除0的情况。在多解的情况下也不对。。
题意:
一个n*n 的木板 ,每个格子 都 可以 染成 白色和黄色,( 一旦我们对也个格子染色 ,他的上下左右 都将改变颜色);
给定一个初始状态 , 求将 所有的 格子 染成黄色 最少需要染几次? 若 不能 染成 输出 inf。
分析:
和1222差不多,唯一的区别是这个题还要求 最短的步数,其实只需要枚举一下最后的x[][]是否为1,即是否需要按下,
由于只有无解或者解唯一,因为按的顺序是没有影响的,所以只要是有解一定唯一,而且最短的情况是每个格子只按一次,
因为按两次以后就变为原来的状态了。
这个是最严谨的这个题的AC代码,因为我做1753的时候用原来的方法错了,看了Kuangbin的博客,知道原来的方法不对,貌似只有一个解和无解的时候才会对。
但是这个是对的:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define LL __int64 const int maxn = 300+10; const int INF = 1<<28; using namespace std; int equ, var, fn; int a[maxn][maxn], x[maxn]; int free_x[maxn]; int gcd(int a, int b) { return b==0?a:gcd(b, a%b); } int lcm(int a, int b) { return a*b/gcd(a, b); } int Gauss() { int x_mo; x_mo = 2; int i, j, k, max_r, col; int ta, tb, LCM, fx_num = 0; col = 0; for(k = 0; k<equ && col<var; k++, col++) { max_r = k; for(i = k+1; i < equ; i++) if(abs(a[i][col])>abs(a[max_r][col])) max_r = i; if(max_r != k) for(j = k; j < var+1; j++) swap(a[k][j], a[max_r][j]); if(a[k][col]==0) { free_x[fx_num++] = col; //求自由变元所在的列 k--; continue; } for(i = k+1; i < equ; i++) { if(a[i][col] != 0) { LCM = lcm(abs(a[i][col]), abs(a[k][col])); ta = LCM/abs(a[i][col]); tb= LCM/abs(a[k][col]); if(a[i][col]*a[k][col] < 0) tb = -tb; for(j = col; j < var+1; j++) a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo; } } } for(i = k; i < equ; i++) if(a[i][col] != 0) return -1; //以下为模2情况下的,枚举变元的方法。 int stat=1<<(var-k);//自由变元有 var-k 个 int res=INF; for(i=0;i<stat;i++)//枚举所有变元 { int cnt=0; int index=i; for(j=0;j<var-k;j++) { x[free_x[j]]=(index&1); if(x[free_x[j]]) cnt++; index>>=1; } for(j=k-1;j>=0;j--) { int tmp=a[j][var]; for(int l=j+1;l<var;l++) if(a[j][l]) tmp^=x[l]; x[j]=tmp; if(x[j])cnt++; } if(cnt<res)res=cnt; } return res; } int main() { int t, i, j, n, tmp; char s[maxn]; scanf("%d", &t); while(t--) { memset(a, 0, sizeof(a)); memset(x, 0, sizeof(x)); scanf("%d", &n); equ = n*n; var = n*n; for(i = 0; i < n; i++) { getchar(); scanf("%s", s); for(j = 0; j < n; j++) { if(s[j]=='y') a[i*n+j][n*n] = 0; //y时为0 else a[i*n+j][n*n] = 1; } } for(i = 0; i < n; i++) for(j = 0; j < n; j++) { tmp = i*n+j; a[tmp][tmp] = 1; if(j<=n-2) a[tmp+1][tmp] = 1; if(j>=1) a[tmp-1][tmp] = 1; if(tmp+n<n*n) a[tmp+n][tmp] = 1; if(tmp-n>=0) a[tmp-n][tmp] = 1; } fn = Gauss(); if(fn==-1) printf("inf\n"); else printf("%d\n", fn); } return 0; }
这个AC代码是我按照模板改的,但是在多解的情况下不对:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define LL __int64 const int maxn = 300+10; using namespace std; int equ, var, fn; int a[maxn][maxn], x[maxn]; int gcd(int a, int b) { return b==0?a:gcd(b, a%b); } int lcm(int a, int b) { return a*b/gcd(a, b); } int Gauss() { int x_mo; x_mo = 2; int i, j, k, max_r, col; int ta, tb, LCM, tmp; col = 0; for(k = 0; k<equ && col<var; k++, col++) { max_r = k; for(i = k+1; i < equ; i++) if(abs(a[i][col])>abs(a[max_r][col])) max_r = i; if(max_r != k) for(j = k; j < var+1; j++) swap(a[k][j], a[max_r][j]); if(a[k][col]==0) { k--; continue; } for(i = k+1; i < equ; i++) { if(a[i][col] != 0) { LCM = lcm(abs(a[i][col]), abs(a[k][col])); ta = LCM/abs(a[i][col]); tb= LCM/abs(a[k][col]); if(a[i][col]*a[k][col] < 0) tb = -tb; for(j = col; j < var+1; j++) a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo; } } } for(i = k; i < equ; i++) if(a[i][col] != 0) return -1; for(i = var-1; i >= 0; i--) { tmp = a[i][var]; for(j = i+1; j < var; j++) if(a[i][j] != 0) tmp = ((tmp-a[i][j]*x[j])%x_mo+x_mo)%x_mo; if(a[i][i]==0) //注意这a[i][i]可能为0, 我改为这样就对了。 x[i] = 0; else { while(tmp%a[i][i]!=0) tmp += x_mo; x[i] = (tmp/a[i][i])%x_mo; } } return 0; } int main() { int t, i, j, n, ans, tmp; char s[maxn]; scanf("%d", &t); while(t--) { memset(a, 0, sizeof(a)); memset(x, 0, sizeof(x)); scanf("%d", &n); equ = n*n; var = n*n; for(i = 0; i < n; i++) { getchar(); scanf("%s", s); for(j = 0; j < n; j++) { if(s[j]=='y') a[i*n+j][n*n] = 0; //y时为0 else a[i*n+j][n*n] = 1; } } for(i = 0; i < n; i++) for(j = 0; j < n; j++) { tmp = i*n+j; a[tmp][tmp] = 1; if(j<=n-2) a[tmp+1][tmp] = 1; if(j>=1) a[tmp-1][tmp] = 1; if(tmp+n<n*n) a[tmp+n][tmp] = 1; if(tmp-n>=0) a[tmp-n][tmp] = 1; } fn = Gauss(); if(fn==-1) printf("inf\n"); else { ans = 0; for(i = 0; i < n*n; i++) if(x[i]==1) //枚举解为1,就是需要将原来的翻转的。 ans ++; printf("%d\n", ans); } } return 0; }
这个AC代码的模板用的是别人的对二取模的模板,用的是 ^异或,不会出现除0的情况。在多解的情况下也不对。。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define LL __int64 const int maxn = 300+10; using namespace std; int equ, var, fn; int a[maxn][maxn], x[maxn]; int gcd(int a, int b) { return b==0?a:gcd(b, a%b); } int lcm(int a, int b) { return a*b/gcd(a, b); } int Gauss() { int i,j,k; int max_r; int col; int temp; int free_x_num; int free_index; col=0; for(k=0;k<equ&&col<var;k++,col++) { max_r=k; for(i=k+1;i<equ;i++) { if(abs(a[i][col])>abs(a[max_r][col]))max_r=i; } if(max_r!=k) { for(j=col;j<var+1;j++)swap(a[k][j],a[max_r][j]); } if(a[k][col]==0) { k--; continue; } for(i=k+1;i<equ;i++) { if(a[i][col]!=0) { for(j=col;j<var+1;j++) a[i][j]^=a[k][j]; } } } for(i=k;i<equ;i++) { if(a[i][col]!=0)return -1; } for(i=var-1;i>=0;i--) { x[i]=a[i][var]; for(j=i+1;j<var;j++) x[i]^=(a[i][j]&&x[j]); } return 0; } int main() { int t, i, j, n, ans, tmp; char s[maxn]; scanf("%d", &t); while(t--) { memset(a, 0, sizeof(a)); memset(x, 0, sizeof(x)); scanf("%d", &n); equ = n*n; var = n*n; for(i = 0; i < n; i++) { getchar(); scanf("%s", s); for(j = 0; j < n; j++) { if(s[j]=='y') a[i*n+j][n*n] = 0; else a[i*n+j][n*n] = 1; } } for(i = 0; i < n; i++) for(j = 0; j < n; j++) { tmp = i*n+j; a[tmp][tmp] = 1; if(j<=n-2) a[tmp+1][tmp] = 1; if(j>=1) a[tmp-1][tmp] = 1; if(tmp+n<n*n) a[tmp+n][tmp] = 1; if(tmp-n>=0) a[tmp-n][tmp] = 1; } fn = Gauss(); if(fn==-1) printf("inf\n"); else { ans = 0; for(i = 0; i < n*n; i++) if(x[i]==1) ans ++; printf("%d\n", ans); } } return 0; }
相关文章推荐
- POJ 1681 Painter's Problem(高斯消元+枚举自由变元)
- poj 1681 Painter's Problem 高斯消元 枚举自由变元
- poj 1681 Painter's Problem 【高斯消元 枚举自由变元】
- poj 1681 Painter's Problem 【高斯消元 + 状压枚举自由变元】
- POJ 1681 Painter's Problem 高斯消元+DFS枚举
- POJ 1753 Flip Game (高斯消元 枚举自由变元求最小步数)
- poj 1681 高斯消元 枚举自由元求翻转最小次
- POJ 1681 Painter's Problem (高斯消元)
- POJ 1681 Painter's Problem 高斯消元 枚举自由变量
- 高斯消元 POJ 1222 POJ 1681(枚举自由变元)POJ 1753(两次高斯消元) POJ 1830 HDU 5833 (高斯消元,素数分解)POJ 3158 (集合压缩枚举自由变元)
- POJ 1681 高斯消元 枚举自由变元
- poj 1681 Painter's Problem(高斯消元)
- POJ 1681 Painter's Problem [高斯消元XOR]
- poj 1681 Painter's Problem (高斯消元)
- Painter's Problem POJ - 1681 高斯消元+枚举自由元
- POJ 1681 Painter's Problem 高斯消元
- poj1753-Flip Game(高斯消元枚举xor线性方程自由变元的值,找为1解的最少数量)
- Painter's Problem POJ - 1681 高斯消元+枚举自由元
- POJ 1681 Painter's Problem,POJ 1222 EXTENDED LIGHTS OUT (高斯消元之异或方程组),高斯消元模板
- poj 1681 Painter's Problem(高斯消元)