这是一类开关问题,对于这类问题可以状态压缩枚举搞,也可以用高斯消元,当数据量比较大的时候高斯消元效率更高。
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;
}
poj 3185
#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;
}