传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1770
思路:繁体字是什么鬼啊....
不过总比英语好...
高斯消元解异或方程组。
把每个灯开关次数看成变量,很显然只会是0和1
然后对于每个灯建立方程,即它和与它相邻的灯的开关次数的异或和为1
但是方程不一定只有唯一解,还会有自由元,就是取什么都会有解。
所以最后还要枚举自由元暴搜
(感觉复杂度会被卡,似乎折半搜更靠谱...不过还好没卡我)
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn=40;
using namespace std;
int n,m,a[maxn][maxn],ans[maxn],tot,mins=10000;
void gauss(){
for (int i=1;i<=n;i++){
int j=i;
for (;j<=n&&!a[j][i];j++);
if (j>n) continue;
if (i!=j) for (int k=1;k<=n+1;k++) swap(a[i][k],a[j][k]);
for (int j=1;j<=n;j++)
if (i!=j&&a[j][i])
for (int k=1;k<=n+1;k++)
a[j][k]^=a[i][k];
}
}
void dfs(int x){
if (tot>=mins) return;
if (!x){mins=min(mins,tot);return;}
if (a[x][x]){
int t=a[x][n+1];
for (int i=x+1;i<=n;i++) if (a[x][i]) t^=ans[i];
ans[x]=t;
if (t) tot++;
dfs(x-1);
if (t) tot--;
}
else{
ans[x]=1,tot++,dfs(x-1),tot--;
ans[x]=0,dfs(x-1);
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) a[i][i]=a[i][n+1]=1;
for (int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),a[x][y]=a[y][x]=1;
gauss(),dfs(n);printf("%d\n",mins);
return 0;
}