[题解](折半搜索/高斯消元枚举自由元)BZOJ_1770_Lights

状压,时间空间都不行,如果每次搜索一半就可以省下很多空间,用map记下每种状态的答案,最后再把两次的答案合并

然而正解是高斯消元解异或方程组,最后搜索自由元

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define ll long long
using namespace std;
const int maxn=40;
const int maxm=600;
int n,m,p,ans=36,fl;
ll f[maxn];
map<ll,int>mx;//每种状态的最小代价 
void dfsl(int x,ll s,int k){
    if(x==m){
        int &t=mx[s];//注意传址的引用 
        if(!t)t=k;
        else if(t>k)t=k;
        return;
    }
    dfsl(x+1,s,k);
    dfsl(x+1,s^f[x],k+1);
}
void dfsr(int x,ll s,int k){
    if(x==m){
        int t=mx[s];
        if(t && t+k-1<ans)ans=t+k-1;
        return;
    }
    dfsr(x+1,s,k);
    dfsr(x+1,s^f[x+m],k+1);
}
int main(){
    scanf("%d%d",&n,&p);
    if(n&1)n++,fl=1;//处理折半搜索 
    m=n/2;
    for(int i=1,x,y;i<=p;i++){
        scanf("%d%d",&x,&y);
        x--,y--;
        f[x]|=1LL<<y,f[y]|=1LL<<x;
    }
    for(int i=0;i<n;i++)f[i]|=1LL<<i;
    dfsl(0,(1LL<<n)-1,1);
    dfsr(0,0,0);
    printf("%d",ans-fl);
}

 

posted @ 2019-05-13 18:46  羊肉汤泡煎饼  阅读(143)  评论(0编辑  收藏  举报