BZOJ1770 : [Usaco2009 Nov]lights 燈

设$f[i]$表示$i$点按下开关后会影响到的点的集合,用二进制表示。

不妨设$n$为偶数,令$m=\frac{n}{2}$,对于前一半暴力$2^m$搜索所有方案,用map维护每种集合的最小代价。

对于后一半暴力$2^m$搜索所有方案,在map中查询补集。

时间复杂度$O(n2^{\frac{n}{2}})$。

 

#include<cstdio>
#include<map>
#define N 36
typedef long long ll;
int n,m,i,x,y,ans=N,flag;ll f[N];std::map<ll,int>T;
void dfsl(int x,ll s,int k){
  if(x==m){
    int&t=T[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=T[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,&i);
  if(n&1)n++,flag=1;
  m=n/2;
  while(i--){
    scanf("%d%d",&x,&y);x--,y--;
    f[x]|=1LL<<y,f[y]|=1LL<<x;
  }
  for(i=0;i<n;i++)f[i]|=1LL<<i;
  dfsl(0,(1LL<<n)-1,1),dfsr(0,0,0);
  return printf("%d",ans-flag),0;
}

  

posted @ 2015-11-08 02:56  Claris  阅读(626)  评论(0编辑  收藏  举报