标签:高斯消元
这是一类开关问题,对于这类问题可以状态压缩枚举搞,也可以用高斯消元,当数据量比较大的时候高斯消元效率更高。
poj 1222
状态压缩枚举第一行所有的翻转情况,从第二行开始依次递推即可。
#include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <algorithm> using namespace std; int dx[5]={0,0,1,-1,0}; int dy[5]={-1,1,0,0,0}; int n,m; int tile[10][10]; int out[10][10]; int flip[10][10]; int get(int x,int y) { int c=tile[x][y]; for(int i=0;i<5;i++) { int tx=x+dx[i],ty=y+dy[i]; if(1<=tx && tx<=n && 1<=ty && ty<=m) c+=flip[tx][ty]; } return c%2; } int cal() { for(int i=2;i<=n;i++) for(int j=1;j<=m;j++) { if(get(i-1,j)!=0) flip[i][j]=1; } for(int i=1;i<=m;i++) if(get(n,i)!=0)return -1; int res=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) res+=flip[i][j]; return res; } void solve() { int res=-1; for(int i=0;i<(1<<m);i++) { memset(flip,0,sizeof(flip)); for(int j=1;j<=m;j++) { flip[1][m-j+1]=(i>>(j-1))&1; } int num=cal(); if(num>=0 && (res<0 || res>num)) { res=num; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) out[i][j]=flip[i][j]; } } } int main() { int T,test=0; cin>>T; while(T--) { n=5,m=6; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>tile[i][j]; } solve(); printf("PUZZLE #%d\n",++test); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(j==1)printf("%d",out[i][j]); else printf(" %d",out[i][j]); } printf("\n"); } } return 0; }也可以高斯消元求解:
模板
#include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <algorithm> using namespace std; const int maxn=50; int equ,var; //equ 个方程,var个未知数,增广矩阵 equ行 var+1列 int a[maxn][maxn]; //系数矩阵 int x[maxn]; //解集 int free_x[maxn]; //存储自由变元 int free_num; // 自由变元的个数 void Debug(void) { int i, j; for (i = 0; i < equ; i++) { for (j = 0; j < var + 1; j++) { cout << a[i][j] << " "; } cout << endl; } cout << endl; } int Gauss() { int max_r,col,k; // 在当前col列中找到一个最大值 用max_r存储这一行 free_num=0; for(k=0,col=0;k<equ&&col<var;k++,col++) //枚举行 化行阶梯 { max_r=k; for(int i=k+1;i<equ;i++) { if(abs(a[i][col])>abs(a[max_r][col])) //减小误差 { max_r=i; } } if(a[max_r][col]==0) //说明该列所对应的x是自由元变量 { k--; free_x[free_num++]=col; continue; } if(max_r!=k) //交换两行 { for(int j=col;j<var+1;j++) swap(a[k][j],a[max_r][j]); } for(int i=k+1;i<equ;i++) { if(a[i][col]!=0) { for(int j=col;j<var+1;j++) a[i][j]=a[i][j]^a[k][j]; } } } for(int i=k;i<equ;i++) { if(a[i][col]!=0)return -1; } if(k<var)return var-k; for(int i=var-1;i>=0;i--) { x[i]=a[i][var]; for(int j=i+1;j<var;j++) x[i]=x[i]^(a[i][j] && x[j]); } return 0; } int main() { int n,test=0; scanf("%d",&n); while(n--) { equ=30,var=30; memset(a,0,sizeof(a)); memset(x,0,sizeof(x)); for(int i=0;i<5;i++) for(int j=0;j<6;j++) { int t; scanf("%d",&t); a[i*6+j][var]=t; a[i*6+j][i*6+j]=1; if(i-1>=0)a[(i-1)*6+j][i*6+j]=1; if(i+1<5)a[(i+1)*6+j][i*6+j]=1; if(j-1>=0)a[i*6+j-1][i*6+j]=1; if(j+1<6)a[i*6+j+1][i*6+j]=1; } Gauss(); //Debug(); printf("PUZZLE #%d\n",++test); for(int i=0;i<5;i++) { for(int j=0;j<6;j++) { if(j==0)printf("%d",x[i*6+j]); else printf(" %d",x[i*6+j]); } printf("\n"); } } return 0; }
枚举自由元变量
#include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <algorithm> using namespace std; const int maxn=400; const int INF=99999999; char s[40][40]; int equ,var; int a[maxn][maxn],n; int x[maxn]; int free_x[maxn]; int free_num; void Debug(void) { int i, j; for (i = 0; i < equ; i++) { for (j = 0; j < var + 1; j++) { cout << a[i][j] << " "; } cout << endl; } cout << endl; } int Gauss() { int max_r,col,k; // 在当前col列中找到一个最大值 用max_r存储这一行 free_num=0; for(k=0,col=0;k<equ&&col<var;k++,col++) //枚举行 化行阶梯 { max_r=k; for(int i=k+1;i<equ;i++) { if(abs(a[i][col])>abs(a[max_r][col])) //减小误差 { max_r=i; } } if(a[max_r][col]==0) //说明该列所对应的x是自由元变量 { k--; free_x[free_num++]=col; continue; } if(max_r!=k) //交换两行 { for(int j=col;j<var+1;j++) swap(a[k][j],a[max_r][j]); } for(int i=k+1;i<equ;i++) { if(a[i][col]!=0) { for(int j=col;j<var+1;j++) a[i][j]=a[i][j]^a[k][j]; } } } for(int i=k;i<equ;i++) { if(a[i][col]!=0)return -1; } if(k<var)return var-k; for(int i=var-1;i>=0;i--) { x[i]=a[i][var]; for(int j=i+1;j<var;j++) x[i]=x[i]^(a[i][j] && x[j]); } return 0; } void init() { memset(a,0,sizeof(a)); memset(x,0,sizeof(x)); for(int i=0;i<4;i++) for(int j=0;j<4;j++) { a[i*4+j][i*4+j]=1; if(i-1>=0)a[(i-1)*4+j][i*4+j]=1; if(i+1<4)a[(i+1)*4+j][i*4+j]=1; if(j-1>=0)a[i*4+j-1][i*4+j]=1; if(j+1<4)a[i*4+j+1][i*4+j]=1; } } int solve() { int num=Gauss(); if(num==-1) { return INF; } else if(num==0) { int cnt=0; for(int i=0;i<n*n;i++)cnt+=x[i]; return cnt; } else //枚举自由元的 { int tot=(1<<free_num),cnt=0,ans=99999999; for(int i=0;i<tot;i++) { cnt=0; for(int j=0;j<free_num;j++) { if( i&(1<<j) ) { x[free_x[j]]=1; cnt++; } else x[free_x[j]]=0; } for(int j=var-free_num-1;j>=0;j--) { int idx; for(idx=j;idx<var;idx++) { if(a[j][idx])break; } x[j]=a[j][var]; for(int l=idx+1;l<var;l++) { if(a[j][l]) x[j]=x[j]^x[l]; } cnt+=x[j]; } ans=min(ans,cnt); } return ans; } } int main() { for(int i=0;i<4;i++)scanf("%s",s[i]); n=4; equ=16,var=16; init(); for(int i=0;i<4;i++) for(int j=0;j<4;j++) { if( s[i][j]=='w' )a[i*4+j][16]=1; else a[i*4+j][16]=0; } int a1=solve(); init(); for(int i=0;i<4;i++) for(int j=0;j<4;j++) { if( s[i][j]=='w' )a[i*4+j][16]=0; else a[i*4+j][16]=1; } int a2=solve(); if(a1==INF && a2==INF) printf("Impossible\n"); else printf("%d\n",min(a1,a2)); return 0; }
#include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <algorithm> using namespace std; const int maxn=50; int equ,var; //equ 个方程,var个未知数,增广矩阵 equ行 var+1列 int a[maxn][maxn]; //系数矩阵 int x[maxn]; //解集 int free_x[maxn]; //存储自由变元 int free_num; // 自由变元的个数 int s[40]; void Debug(void) { int i, j; for (i = 0; i < equ; i++) { for (j = 0; j < var + 1; j++) { cout << a[i][j] << " "; } cout << endl; } cout << endl; } int Gauss() { int max_r,col,k; // 在当前col列中找到一个最大值 用max_r存储这一行 free_num=0; for(k=0,col=0;k<equ&&col<var;k++,col++) //枚举行 化行阶梯 { max_r=k; for(int i=k+1;i<equ;i++) { if(abs(a[i][col])>abs(a[max_r][col])) //减小误差 { max_r=i; } } if(a[max_r][col]==0) //说明该列所对应的x是自由元变量 { k--; free_x[free_num++]=col; continue; } if(max_r!=k) //交换两行 { for(int j=col;j<var+1;j++) swap(a[k][j],a[max_r][j]); } for(int i=k+1;i<equ;i++) { if(a[i][col]!=0) { for(int j=col;j<var+1;j++) a[i][j]=a[i][j]^a[k][j]; } } } for(int i=k;i<equ;i++) { if(a[i][col]!=0)return -1; } if(k<var)return var-k; for(int i=var-1;i>=0;i--) { x[i]=a[i][var]; for(int j=i+1;j<var;j++) x[i]=x[i]^(a[i][j] && x[j]); } return 0; } void init() { memset(a,0,sizeof(a)); memset(x,0,sizeof(x)); for(int i=0;i<20;i++) { a[i][i]=1; if(i-1>=0)a[i-1][i]=1; if(i+1<20)a[i+1][i]=1; if(s[i])a[i][20]=1; else a[i][20]=0; } } int solve() { int num=Gauss(); if(num==-1) { return -1; } else if(num==0) { int cnt=0; for(int i=0;i<20;i++)cnt+=x[i]; return cnt; } else //枚举自由元的 { int tot=(1<<free_num),cnt=0,ans=99999999; for(int i=0;i<tot;i++) { cnt=0; for(int j=0;j<free_num;j++) { if( i&(1<<j) ) { x[free_x[j]]=1; cnt++; } else x[free_x[j]]=0; } for(int j=var-free_num-1;j>=0;j--) { int idx; for(idx=j;idx<var;idx++) { if(a[j][idx])break; } x[j]=a[j][var]; for(int l=idx+1;l<var;l++) { if(a[j][l]) x[j]=x[j]^x[l]; } cnt+=x[j]; } ans=min(ans,cnt); } return ans; } } int main() { equ=20,var=20; for(int i=0;i<20;i++)scanf("%d",&s[i]); init(); int num=solve(); printf("%d\n",num); return 0; }
标签:高斯消元
原文地址:http://blog.csdn.net/liusuangeng/article/details/44132501