bzoj1770: [Usaco2009 Nov]lights 灯
传送门: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; }