刚刚上一篇博客才D了队长一发,心里虚的慌......万分感谢队长给讲折半搜索!!听说这题可以高斯消元(可是我不会...貌似折半我也不会)
这题呢,一想到就是爆搜啦,然而,爆搜2^35必跪,折半搜索,就让他变成了2^17+2^18,这下明白一点了吧,然后假设现在要从全灭到全开,状压一下就是一个LL的数了,然后从00000~10101(假设嘛)我们只按左边的按钮,11111~01010只按右边的,那加起来不就是答案啦。
#include<map> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; LL Bin[40]; int cnt,mn; LL p[40],ed;//状压,p[i]代表假如我按i,会对那些造成影响就在相应位上记为1 bool half; map<LL,int>f; void dfs(int x,LL now,int d) { if(x==cnt+1) { if(now==ed)mn=min(mn,d);//到达 else { if(half==false)//第一次,记录到达该状态的最优方案 { int c=f[now]; if(c==0||c>d)f[now]=d; } else //第二次,看看我和其他合并能否到达最终状态 { int c=f[ed-now]; if(c!=0)mn=min(mn,c+d); } } return ; } dfs(x+1,now,d);//穷举状态 dfs(x+1,now^p[x],d+1); } int main() { int n,m,x,y; scanf("%d%d",&n,&m); p[1]=Bin[1]=1;for(int i=2;i<=n+1;i++)p[i]=Bin[i]=Bin[i-1]*2; ed=Bin[n+1]-1;//结束状态就是全为1 for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); p[x]+=Bin[y];p[y]+=Bin[x];//记录所影响的 } mn=2147483647; half=false;cnt=n/2;dfs(1,0,0);//折半搜索 half=true;cnt=n;dfs(n/2+1,0,0); printf("%d ",mn); return 0; }