【高斯消元】BZOJ 1770: [Usaco2009 Nov]lights 燈
Description
貝希和她的閨密們在她們的牛棚中玩遊戲。但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了。貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望。她希望您能夠幫幫她,把所有的燈都給重新開起來!她才能繼續快樂地跟她的閨密們繼續玩遊戲! 牛棚中一共有N(1 <= N <= 35)盞燈,編號為1到N。這些燈被置於一個非常複雜的網絡之中。有M(1 <= M <= 595)條很神奇的無向邊,每條邊連接兩盞燈。 每盞燈上面都帶有一個開關。當按下某一盞燈的開關的時候,這盞燈本身,還有所有有邊連向這盞燈的燈的狀態都會被改變。狀態改變指的是:當一盞燈是開著的時候,這盞燈被關掉;當一盞燈是關著的時候,這盞燈被打開。 問最少要按下多少個開關,才能把所有的燈都給重新打開。 數據保證至少有一種按開關的方案,使得所有的燈都被重新打開。
Input
*第一行:兩個空格隔開的整數:N和M。
*第二到第M+1行:每一行有兩個由空格隔開的整數,表示兩盞燈被一條無向邊連接在一起。 沒有一條邊會出現兩次。
Output
第一行:一個單獨的整數,表示要把所有的燈都打開時,最少需要按下的開關的數目。
其实是和POJ1222差不多的一题。
但是这题有一些解是自由的(不管是什么都不影响解)。
所以我们高斯消元后bfs。
枚举自由元的情况(按和不按),更新最优解。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 6 using namespace std; 7 8 int ga[100][100],cnt=0,ans,s[100],n; 9 10 void guass() 11 { 12 for(int i=1;i<=n;i++) 13 { 14 int j=i; 15 while(ga[j][i]==0&&j<=n)j++; 16 if(j>n)continue; 17 if(j!=i) 18 { 19 for(int k=1;k<=n+1;k++) 20 swap(ga[i][k],ga[j][k]); 21 } 22 if(!ga[i][i])continue; 23 for(j=1;j<=n;j++) 24 if(ga[j][i]&&j!=i) 25 for(int k=1;k<=n+1;k++) 26 ga[j][k]=ga[j][k]^ga[i][k]; 27 } 28 } 29 30 void dfs(int x) 31 { 32 if(cnt>=ans)return; 33 if(x==0) 34 { 35 ans=min(ans,cnt); 36 return; 37 } 38 if(ga[x][x]) 39 { 40 int num=ga[x][n+1]; 41 for(int i=x+1;i<=n;i++) 42 if(ga[x][i]) 43 num=num^s[i]; 44 s[x]=num; 45 if(num==1)cnt++; 46 dfs(x-1); 47 if(num==1)cnt--; 48 } 49 if(!ga[x][x]) 50 { 51 s[x]=0;dfs(x-1); 52 s[x]=1;cnt++;dfs(x-1);cnt--; 53 } 54 } 55 56 int main() 57 { 58 int m,x,y; 59 scanf("%d%d",&n,&m); 60 for(int i=1;i<=n;i++) 61 ga[i][i]=1,ga[i][n+1]=1; 62 for(int i=1;i<=m;i++) 63 scanf("%d%d",&x,&y),ga[x][y]=ga[y][x]=1; 64 guass(); 65 ans=1<<30;dfs(n); 66 printf("%d",ans); 67 return 0; 68 }
忽略函数名字2333。。