BZOJ 1770: [Usaco2009 Nov]lights 燈

1770: [Usaco2009 Nov]lights 燈

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 840  Solved: 397
[Submit][Status][Discuss]

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

Gold

分析:

我们记$x[i]$为$i$的翻转次数,显然只可能是$0$和$1$,于是我们得到一个$xor$方程:$x[i] xor x[j] xor …… xor x[k]=0/1$,($j……k$代表和$i$直接有边相连的点),$0$就代表最终状态和初始状态相同,$1$代表不同,这样,我们就得到了$n$个异或方程,然后高斯消元解除每个开关点是否需要翻转,消完之后会有自由元也就是无论翻转与否都有一种对应的合法方案的点,对于这种的点我们通过$dfs$来得到最优方案...

我们$dfs$的时候,对于一个主元是否需要翻转我们可以计算得出的,也就是它周围的点对它的影响如果和它本身想要达到的状态不同就需要付出$1$的代价,否则就不用了,由于我们高斯消元的时候把一个$n*n$的矩阵消成了一个对角矩阵,并且$a[i][n+1]$代表第$i$个点是否需要翻转,同时它也代表了所有的是主元的并且和$i$直接有边相连的点对$i$的影响,而$a[i][i]$代表当前的点是否为主元,而且高斯消元完之后的对角矩阵的对角线是由前缀$1$和后缀$0$组成的,所以我们倒着搜索,这样枚举到主元的时候所有的自由元是否翻转已经确定了,所以我们就可以计算所有的和$i$有边相连的点对$i$的影响...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=35+5;

int n,m,ans,a[maxn][maxn],tmp[maxn];

inline void gauss(void){
	for(int i=1;i<=n;i++){
		int k=i;
		while(!a[k][i]&&k<=n)
			k++;
		if(a[k][i]){
			if(k!=i)
				for(int s=1;s<=n+1;s++)
					swap(a[k][s],a[i][s]);
			for(int l=1;l<=n;l++)
				if(l!=i&&a[l][i])
					for(int s=1;s<=n+1;s++)
						a[l][s]^=a[i][s];
		}
	}
}

inline void dfs(int id,int cnt){
	if(cnt>=ans)
		return;
	if(id==0){
		ans=min(ans,cnt);
		return;
	}
	if(a[id][id]){
		tmp[id]=a[id][n+1];
		for(int i=n;i>id;i--)
			if(a[id][i])
				tmp[id]^=tmp[i];
		dfs(id-1,cnt+tmp[id]);
	}
	else
		tmp[id]=0,dfs(id-1,cnt),
		tmp[id]=1,dfs(id-1,cnt+1);
}

signed main(void){
	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;
	ans=n+1;gauss();dfs(n,0);printf("%d\n",ans);
	return 0;
}

  



By NeighThorn

时间: 2024-08-07 11:33:02

BZOJ 1770: [Usaco2009 Nov]lights 燈的相关文章

BZOJ 1770: [Usaco2009 Nov]lights 燈( 高斯消元 )

高斯消元解xor方程组...暴搜自由元+最优性剪枝 ----------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<bitset> using namespace std; const int maxn = 49; int N, Id[max

BZOJ 1770 [Usaco2009 Nov]lights 燈 【高斯消元】

Description 貝希和她的閨密們在她們的牛棚中玩遊戲.但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了.貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望.她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N.這些燈被置於一個非常複雜的網絡之中.有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈. 每盞燈上面都帶有一個開關.當

【高斯消元】BZOJ 1770: [Usaco2009 Nov]lights 燈

Description 貝希和她的閨密們在她們的牛棚中玩遊戲.但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了.貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望.她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N.這些燈被置於一個非常複雜的網絡之中.有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈. 每盞燈上面都帶有一個開關.當

BZOJ 1770: [Usaco2009 Nov]lights 燈 [高斯消元XOR 搜索]

题意: 经典灯问题,求最少次数 本题数据不水,必须要暴搜自由元的取值啦 想了好久 然而我看到网上的程序都没有用记录now的做法,那样做遇到自由元应该可能会丢解吧...? 我的做法是把自由元保存下来,枚举的时候只枚举自由元 但这样没法最优性剪枝了 于是枚举的时候还是从n到1枚举,到i时如果i是主元这时候i的值已经可以算出来了,这样就可以最优性剪枝了 但注意主元i你不能用i这个方程,而要保存pivot[i]为i用了哪个方程 然后一个伪贪心策略是自由元先搜0 #include <iostream>

bzoj 1770 [Usaco2009 Nov]lights 燈 meet in the middle

题面 题目传送门 解法 题解里都是高斯消元然后dfs,蒟蒻表示不会 直接分两半dfs即可 时间复杂度:\(O(2^{\frac{n}{2}})\) 代码 #include <bits/stdc++.h> #define LL long long #define N 110 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y);} template &

BZOJ1770 : [Usaco2009 Nov]lights 燈

设$f[i]$表示$i$点按下开关后会影响到的点的集合,用二进制表示. 不妨设$n$为偶数,令$m=\frac{n}{2}$,对于前一半暴力$2^m$搜索所有方案,用map维护每种集合的最小代价. 对于后一半暴力$2^m$搜索所有方案,在map中查询补集. 时间复杂度$O(n2^{\frac{n}{2}})$. #include<cstdio> #include<map> #define N 36 typedef long long ll; int n,m,i,x,y,ans=N,

bzoj:2018: [Usaco2009 Nov]农场技艺大赛

Description Input 第1行:10个空格分开的整数: N, a, b, c, d, e, f, g, h, M Output 第1行:满足总重量最轻,且用度之和最大的N头奶牛的总体重模M后的余数. Sample Input 2 0 1 5 55555555 0 1 0 55555555 55555555 Sample Output 51 HINT 样例说明:公式生成的体重和有用度分别为: 体重:5, 6, 9, 14, 21, 30 有用度:0, 1, 8, 27, 64, 125

BZOJ 2017: [Usaco2009 Nov]硬币游戏(A Coin Game)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2017 参考题解:http://www.mamicode.com/info-detail-1582288.html 解:看的时候觉得是动归,然而不会设也不会列,看了半天别人的题解... 首先我们用f[i][j]来表示还剩下后i个硬币要取,上一步取了j个硬币,接下来的步骤中能获得的最大价值. 然后呢,假设在这一步是第一个人取,要取k个,k<=min(2*j,i),很显然,因为第二个人也会取最

[Usaco2009 Nov]lights(高斯消元)

luogu 点灯游戏应该很多人都在小时候頽过吧 反正我直到现在也不会 很明显一个灯最多只需要点一次 然后高斯消元 解完肯定剩自由元(就是那些全是0的行) 然后这些都爆搜 由于剩下的自由元不会太多 所以时间复杂度$O(能过)$ 以上 1 #include<cstdio> 2 #include<algorithm> 3 using std::swap; 4 const int N=40; 5 template<typename tp>void read(tp &kk