[题解](折半搜索/高斯消元枚举自由元)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); }