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; }