1. 程式人生 > >bzoj 1770: [Usaco2009 Nov]lights 燈

bzoj 1770: [Usaco2009 Nov]lights 燈

line 如果 bbs wap 表示 opened scanf while log

1770: [Usaco2009 Nov]lights 燈

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 976 Solved: 463
[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上面的開關。
     這道題講真看不出來是爆搜,唯一的提示就是N很小,但又大於狀壓範圍,可能需要爆搜。
  這道題正解是異或高斯消元+DFS。很明顯一個燈要麽不按,要麽就按一次,所以我們很容易想到高斯消元,由於這道題要求都亮所以異或和之後的結果都為1。通過異或高斯消元我們就可以知道那些點對於某個點是否真正有影響,那些點自己是否開對自己是否有影響,然後我們就可以對於每個自己開不開都對自己沒影響的點(自由元)進行枚舉,看他們開ans小還是關ans小,而對於每一個我們已知對自己有影響的就去看他是否被我們打開,由於高斯消元之後是一個倒三角形,我們只用從他之後那位開始找就好了,如果前幾個開開他是關上的我們就把他打開,否則就把他關上,最終輸出答案即可。    技術分享
 1 #include<iostream>
 2
#include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #define N 50 10 using namespace std; 11 int n,m,ans=0x7ffffff; 12 int a[N][N],ope[N]; 13 void dfs(int sum,int wz) 14 { 15 if(sum>=ans)return; 16 if(wz==0) 17 { 18 ans=sum;return; 19 } 20 if(a[wz][wz]) 21 { 22 int l=a[wz][n+1]; 23 for(int i=wz+1;i<=n;i++) if(a[wz][i]) l^=ope[i]; 24 if(l) 25 { 26 ope[wz]=1; 27 sum++; 28 } 29 dfs(sum,wz-1); 30 if(l) 31 { 32 ope[wz]=0; 33 sum--; 34 } 35 } 36 else 37 { 38 ope[wz]=1;sum++;dfs(sum,wz-1); 39 ope[wz]=0;sum--;dfs(sum,wz-1); 40 } 41 } 42 void gx() 43 { 44 for(int i=1;i<=n;i++) 45 { 46 int bj=i; 47 while(bj<=n&&!a[bj][i])bj++; 48 if(bj>n)continue; 49 if(bj!=i) 50 { 51 for(int j=1;j<=n+1;j++) 52 { 53 swap(a[i][j],a[bj][j]); 54 } 55 } 56 for(int j=1;j<=n;j++) 57 { 58 if(i==j||!a[j][i])continue; 59 for(int k=1;k<=n+1;k++) 60 a[j][k]^=a[i][k]; 61 } 62 } 63 } 64 int main() 65 { 66 scanf("%d%d",&n,&m); 67 for(int i=1;i<=m;i++) 68 { 69 int x,y; 70 scanf("%d%d",&x,&y); 71 a[x][y]=a[y][x]=1; 72 } 73 for(int i=1;i<=n;i++) 74 a[i][i]=1,a[i][n+1]=1; 75 gx(); 76 dfs(0,n); 77 printf("%d\n",ans); 78 return 0; 79 }
View Code

bzoj 1770: [Usaco2009 Nov]lights 燈