bzoj1770: [Usaco2009 Nov]lights 燈(折半搜索)

1770: [Usaco2009 Nov]lights 燈

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1153  Solved: 564
[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

/*
折半搜索经典题
注意每个点随时都可以去。
搜一半,map记录这一半所有状态的最小步数。
搜另一半时,用当前状态步数+记录好的当前补集步数即可。 
*/
#include<bits/stdc++.h>

#define inf 1000000000
#define N 40
#define ll long long

using namespace std;
int n,m,cnt,ans=inf;
int a[N];
bool flag;
ll ed,p[N],bin[N];
map<ll,int>step;

inline 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*10+ch-'0';ch=getchar();}
    return x*f;
}

void dfs(int x,ll sta,int tot)//sta是当前状态,ed是末状态 
{
    if(x==cnt+1)
    {
        if(sta==ed)ans=min(tot,ans);
        if(!flag)
        {
            int t=step[sta];
            if(!t || t>tot)step[sta]=tot;
        }
        else
        {
            int t=step[ed-sta];//取记录好的当前状态的补集 
            if(!t)return;
            ans=min(t+tot,ans);
        }
        return;
    }
    dfs(x+1,sta,tot);
    dfs(x+1,sta^p[x],tot+1);
}

int main()
{
    bin[1]=1;for(int i=2;i<40;i++)bin[i]=bin[i-1]<<1;
    n=read();m=read();
    ed=bin[n+1]-1;
    for(int i=1;i<=m;i++)
    {
        int a=read(),b=read();
        p[a]|=bin[b];p[b]|=bin[a];//记录每个点能改变那些点的状态 
    }
    for(int i=1;i<=n;i++)p[i]+=bin[i];//也能改变当前点的状态 
    cnt=n/2;dfs(1,0,0);
    flag=1;
    cnt=n;dfs(n/2+1,0,0);
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/L-Memory/p/9877089.html