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;
}


posted @ 2015-07-29 11:21  orzpps  阅读(226)  评论(0编辑  收藏  举报