【bzoj1770/Usaco2009 Nov】lights 燈——折半搜索

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上面的開關。
 

听说是高斯消元?不会写,留坑待填......
写了折半,大概就是先搜前一半点的状态即其代价,f[i]表示状态i的最小代价;
搜索后一半点的时候代价就是当前状态加上状态补集的代价。
再加个hash判重就可以啦。
代码:
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 typedef long long LL;
 5 const int N=36,mod=9875321;
 6 using std::min;
 7 int n,m,mni=0x3f3f3f3f,h;
 8 int hash[mod],tot=0,an[600000];
 9 struct node{int ne;LL to;}e[600000];
10 LL all;
11 int read(){
12     int ans=0,f=1;char c=getchar();
13     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
14     while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();}
15     return ans*f;
16 }
17 LL f[N];
18 int Hash(LL x){
19     int p=x%mod;
20     for(int i=hash[p];i;i=e[i].ne)if(e[i].to==x)return i;
21     e[++tot]=(node){hash[p],x};hash[p]=tot;
22     return tot;
23 }
24 void dfs(int x,LL now,int st,int p){
25     if(st>mni)return;
26     if(x==h+1){
27         LL no=now;no>>=1;
28         if(no==all)mni=min(mni,st);
29         if(!p){
30             int k=Hash(no);
31             if(an[k])an[k]=min(an[k],st);
32             else an[k]=st;
33         }
34         else{
35             int k=Hash(all-no);
36             if(!an[k])return;
37             mni=min(mni,st+an[k]);
38         }
39         return;
40     }
41     dfs(x+1,now,st,p);dfs(x+1,now^f[x],st+1,p);
42 }
43 int main(){
44     n=read();m=read();all=(1LL<<n)-1;
45     for(int i=1,a,b;i<=m;i++){
46         a=read();b=read();f[a]|=(1LL<<b);f[b]|=(1LL<<a);
47     }
48     for(int i=1;i<=n;i++)f[i]|=(1LL<<i);
49     h=n/2;dfs(1,0,0,0);h=n;dfs(n/2+1,0,0,1);
50     printf("%d",mni);
51     return 0;
52 }
53 
bzoj1770

 

posted @ 2017-10-14 08:07  Child-Single  阅读(181)  评论(0编辑  收藏  举报