【NKOJ1987 POJ1681】手机游戏(Painter's Problem) 高斯消元
高斯消元,消来消去真有趣,突然想去玩祖玛。
POJ传送门http://poj.org/problem?id=1681
NKOJ传送门http://oi.nks.edu.cn/zh/Problem/Details/1987
一个高斯消元解异或方程组板题。
真的没有什么好说的。就说说时间复杂度。看似O(n6)的时间复杂度,但我们可以注意到,每一个点最多关联上下左右自己5个方程式,也就说实际上它的时间复杂度是O(n4)加上一个常数(可见大概为5)。
记得要枚举自由元!用DFS比较好理解,也有状压的写法,DFS原型来自ciocio学长。
#include<cstring> #include<iostream> #include<cstdio> using namespace std; int n,N,X[2005]; int A[2005][2005]; int dx[4]={1,-1,0,0}; int dy[4]={0,0,-1,1}; int aha=0; int minn; int num[2005]; int ans[2005]; void dfs(int x,int y) { if(x==0&&y==0) { int cnt=0; for(int i=1;i<=N;i++) cnt+=ans[i]; minn=min(minn,cnt); return; } if(num[x]==y) { ans[y]=A[x][N+1]; for(int i=y+1;i<=N;i++) ans[y]^=(A[x][i]&ans[i]); dfs(x-1,y-1); } else { ans[y]=1; dfs(x,y-1); ans[y]=0; dfs(x,y-1); } }// from ciocio void gauss() { int x,y,maxr; for(x=1,y=1;x<=N&&y<=N;x++,y++) { for(maxr=x;maxr<=N&&(!A[maxr][y]);maxr++); if(maxr==N+1) { x--; continue; } if(maxr!=x) for(int j=y;j<=N+1;j++) swap(A[x][j],A[maxr][j]); num[x]=y; for(int i=x+1;i<=N;i++) { if(A[i][y]) for(int j=y;j<=N+1;j++) A[i][j]^=A[x][j]; } } for(int i=x;i<=N;i++) if(A[i][N+1]) { printf("inf\n"); return; }; minn=0x3f3f3f3f; dfs(x-1,N); printf("%d\n",minn); } int main() { char ch; scanf("%d",&n); N=n*n; for(int i=1;i<=n*n;i++) A[i][n*n+1]=1; int nx,ny; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { for(int tt=0;tt<4;tt++) { nx=i+dx[tt]; ny=j+dy[tt]; if(nx>=1&&ny>=1&&nx<=n&&ny<=n) { A[(i-1)*n+j][(nx-1)*n+ny]=1; } } A[(i-1)*n+j][(i-1)*n+j] = 1; } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { ch=getchar(); while(ch!='y'&&ch!='w') ch=getchar(); if(ch=='y') A[(i-1)*n+j][N+1]=0; else A[(i-1)*n+j][N+1]=1; } } gauss(); }