BZOJ 1770 [Usaco2009 Nov] lights 燈

40 篇文章 0 订阅
8 篇文章 0 订阅

Description

貝希和她的閨密們在她們的牛棚中玩遊戲。但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了。貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望。她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N。這些燈被置於一個非常複雜的網絡之中。有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈。 每盞燈上面都帶有一個開關。當按下某一盞燈的開關的時候,這盞燈本身,還有所有有邊連向這盞燈的燈的狀態都會被改變。狀態改變指的是:當一盞燈是開著的時候,這盞燈被關掉;當一盞燈是關著的時候,這盞燈被打開。 問最少要按下多少個開關,才能把所有的燈都給重新打開。 數據保證至少有一種按開關的方案,使得所有的燈都被重新打開。

Input

*第一行:兩個空格隔開的整數:N和M。

*第二到第M+1行:每一行有兩個由空格隔開的整數,表示兩盞燈被一條無向邊連接在一起。 沒有一條邊會出現兩次。

Output

第一行:一個單獨的整數,表示要把所有的燈都打開時,最少需要按下的開關的數目。

Sample Input

5 6
1 2
1 3
4 2
3 4
2 5
5 3

輸入細節:

一共有五盞燈。燈1、燈4和燈5都連接著燈2和燈3。

Sample Output

3

輸出細節:

按下在燈1、燈4和燈5上面的開關。

HINT

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

高斯消元解异或方程组+dfs~

前半部分和上一道一样,但是这道有自由元,就是有可开可不开的灯,所以我们要dfs最后是否每盏灯都要开。

注意dfs的时候用x[i]记录,不能改变原来的a[i][j]数组。


#include<cstdio>
#include<iostream>
using namespace std;

int n,m,a[36][37],xx,yy,ans,x[36];

int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}

void guass()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		  if(a[j][i]>a[i][i])
		    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=i;k<=n+1;k++) a[j][k]^=a[i][k];
	}
}

void dfs(int u,int v)
{
	if(v>=ans) return;
	if(!u)
	{
		ans=v;return;
	}
	if(a[u][u])
	{
		x[u]=a[u][n+1];
		for(int j=u+1;j<=n;j++) x[u]^=a[u][j]&x[j];
		dfs(u-1,v+x[u]);
	}
	else
	{
		x[u]=1;dfs(u-1,v+1);
		x[u]=0;dfs(u-1,v);
	}
}

int main()
{
	n=read();m=read();ans=n;
	for(int i=1;i<=n;i++) a[i][i]=a[i][n+1]=1;
	for(int i=1;i<=m;i++) xx=read(),yy=read(),a[xx][yy]=a[yy][xx]=1;
	guass();dfs(n,0);
	printf("%d\n",ans);
	return 0;
}


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值