Description
Their snouts, though, are so wide that they flip not only one bowl but also the bowls on either side of that bowl (a total of three or -- in the case of either end bowl -- two bowls).
Given the initial state of the bowls (1=undrinkable, 0=drinkable -- it even looks like a bowl), what is the minimum number of bowl flips necessary to turn all the bowls right-side-up?
Input
Output
Sample Input
0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0
Sample Output
3
Hint
Flip bowls 4, 9, and 11 to make them all drinkable:
0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 [initial state]
0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 [after flipping bowl 4]
0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 [after flipping bowl 9]
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [after flipping bowl 11]
Source
典型的高消解异或方程组,需要枚举自由变元。
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=30;
int x[maxn];//存最后的解
int mat[maxn][maxn];
int free_x[maxn];//存自由变元
int Gauss(int equ,int var)
{
int i,j,k;
int free_index,free_num;
int max_r,col,num;
col=0;
num=0;
memset(x,0,sizeof(x));
for(int i=0;i<var+1;i++)
{
x[i]=0;
free_x[i]=0;
}
for(k=0;k<equ && col<var;k++,col++)
{
max_r=k;//找到col列上绝对值最大的那行(k行的下面那些行)
for(i=k+1;i<equ;i++)
{
if(abs(mat[i][col]) > abs(mat[max_r][col]))
max_r=i;
}
if(max_r!=k)//找到后和第k行交换
{
for(j=k;j<var+1;j++)
swap(mat[k][j],mat[max_r][j]);
}
if(!mat[k][col])
{
k--;
free_x[num++]=col;//如果第k行第col这个数为0,也就是系数为0,那他就是个自由变量
continue;
}
for(i=k+1;i<equ;i++)
{
if(mat[i][col])
{
for(j=col;j<var+1;j++)
mat[i][j]^=mat[k][j];//异或以后消去k+1行到最后一行的第col列的系数,形成上三角矩阵
}
}
}
for(i=k;i<equ;i++)
if(mat[i][col])
return -1;//无解
//接下来得枚举自由变元
int all=1<<(var-k);//var-k个自由变元,那么有2的指数次个状态
int res=0x3f3f3f3f;
for(i=0;i<all;i++)
{
int cnt=0;
int index=i;
for(j=0;j<var-k;j++)
{
x[free_x[j]]=(index&1);
if(index&1)//如果是1,则要反转,也就是要操作一次
cnt++;
index>>=1;
}
//同时还要判断确定的变量
for(j=k-1;j>=0;j--)
{
int temp=mat[j][var];
for(int l=j+1;l<var;l++)
if(mat[j][l])
temp^=mat[j][l]*x[l];
x[j]=temp;
if(x[j])
cnt++;
}
if(cnt < res)
res = cnt;
}
return res;
}
int num[22];
int main()
{
while(~scanf("%d",&num[0]))
{
memset(mat,0,sizeof(mat));
for(int i=1;i<20;i++)
scanf("%d",&num[i]);
for(int i=0;i<20;i++)
{
mat[i][i]=1;
if(i>0)
mat[i][i-1]=1;
if(i<19)
mat[i][i+1]=1;
}
for(int i=0;i<20;i++)
mat[i][20]=num[i];
int res=Gauss(20,20);
printf("%d\n",res);
}
return 0;
}