经典开关问题,不过这回给出的是一行开关而不是矩阵开关。高斯消元枚举自由变元
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int n = 20;
int a[22][22] , x[22], freex[22],xx[22];
void debug()
{
puts("debug");
int i,j;
for(i = 0;i < n; i++)
{
for(j = 0;j < n+1;j ++)
printf("%d ",a[i][j]);
puts("");
}
puts("end");
}
void gauss()
{
int i,j,l;
int row = 0, col = 0;
// debug();
for(; row < n && col < n; row++, col++)
{
int maxr = row;
for(i = row+1;i < n; i++)
if(a[i][col])
maxr = i;
if(!a[maxr][col])
{
row --;
continue;
}
if(row != maxr)
for(i = col;i < n+1;i ++)
swap(a[maxr][i] , a[row][i]);
for(i = row+1;i < n ;i++)
if(a[i][col])
for(j = col;j < n+1; j++)
a[i][j] ^= a[row][j];
}
// debug();
int ans = 0;
for(i = n-1;i >= 0; i--)
{
x[i] = a[i][n];
for(j = i+1;j < n; j++)
if(x[j] && a[i][j])
x[i] ^= 1;
if(x[i])
ans ++;
}
for(i = 0;i < n; i++)
freex[i] = 1;
for(i = row-1;i >= 0; i--)
{
int num = 0 , id;
for(j = i;j < n; j++)
if(a[i][j] && freex[j])
num ++ , id = j;
if(num > 1)
continue;
x[id] = a[i][n];
for(j = id+1;j < n; j++)
if(a[i][j])
x[id] ^= 1;
freex[id] = 0;
}
int num = 0;
int k = n-row;
int N = 1<<k;
for(i = n-1;i >= 0 && num < k;i--)
if(freex[i])
xx[num++] = i;
for(j = i;j >= 0; j--)
freex[i] = 0;
for(i = 0;i < N; i++)
{
int sum = 0;
for(j = 0;j < k; j++)
if(i & (1<<j))
x[xx[j]] = 1,sum++;
else
x[xx[j]] = 0;
for(j = row-1;j >= 0;j --)
{
for(l = j;l < n; l++)
if(a[j][l])
break;
int id = l;
x[id] = a[j][n];
for(l = id+1;l < n; l++)
if(a[j][l] && x[l])
x[id] ^= 1;
if(x[id])
sum++;
}
if(sum < ans)
ans = sum;
}
printf("%d\n", ans);
}
int main()
{
int i;
memset(a,0,sizeof(a));
for(i = 0;i < n; i++)
scanf("%d", &a[i][20]);
for(i = 0;i < n ;i++)
{
a[i][i] = 1;
if(i > 0)
a[i][i-1] = 1;
if(i < n-1)
a[i][i+1] = 1;
}
gauss();
return 0;
}