题意:给定一个0 1 串。每次可以选择一个位置改变左右相邻位置及本身的状态,问全变为0,至少需要选几个。
思路:枚举自由变元,取最小的
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 25;
int a[maxn][maxn];
int free_x[maxn];
int x[maxn];
int Gauss(int equ,int var)
{
int maxrow;
int row=0,col=0,num=0;
for(;row<equ&&col<var;row++,col++)
{
maxrow=row;
for(int k=row+1;k<equ;k++)
if(abs(a[k][col])>abs(a[maxrow][col]))maxrow=k;
if(maxrow!=row)
{
for(int j=row;j<=var;j++)//
swap(a[maxrow][j],a[row][j]);
}
if(a[row][col]==0)
{
row--;
free_x[num++]=col;//说明“对角线”上系数为0
continue;
}
for(int i=row+1;i<equ;i++)
{
if(a[i][col]!=0)
{
for(int j=0;j<=var;j++)
a[i][j]=a[i][j]^a[row][j];
}
}
}
int s=1<<(var-row);
int min = 1<<30;
for(int i=0;i<s;i++)//二进制枚举所有自由变元取值
{
int cnt=0;
int index=i;
for(int j=0;j<var-row;j++)
{
x[free_x[j]]=(index&i);
if(x[free_x[j]])cnt++;
index>>=1;
}
for(int k=row-1;k>=0;k--)
{
int temp=a[k][var];
for(int j=k+1;j<var;j++)
temp^=(x[j]*a[k][j]);
x[k]=temp;
if(x[k])cnt++;
}
if(cnt<min)
{
min=cnt;
}
}
return min;
}
int main()
{
int temp;
for(int i=0;i<20;i++)
{
scanf("%d",&temp);
if(temp)
a[i][20]=1;
}
for(int i=0;i<20;i++)
{
a[i][i]=1;
if(i<19)a[i+1][i]=1;
if(i>0)a[i-1][i]=1;
}
int ans = Gauss(20,20);
printf("%d\n",ans);
}