bzoj 3149: [Ctsc2013]复原 dfs

来源:互联网 发布:linux cp覆盖文件 编辑:程序博客网 时间:2024/05/16 12:01

       虽然表算是神奇的分组但是只要搜搜搜就过去了。。。

       每个连通块分别考虑,然后枚举这一条弦的两个端点;如果一个端点已经确定,那么另一个端点的范围必然是一个区间,用位运算加速即可。然后就过了。。。

       最大独立集的话子集dp一下就好了。。

AC代码如下:

#include<iostream>#include<cstdio>#include<cstring>#define N 25#define M 1300005using namespace std;int n,m,len,cnt,bin[N],lg2[M],f[M],h[N],mp[N],pth[N<<1],ans[N<<1];bool a[N][N],vis[N];void up(int &x,int y){ if (x<y) x=y; }bool dfs(int k,int lmt){if (k>lmt) return 1;len++; int i,j,s;for (i=len; i>1; i--) pth[i]=pth[i-1];for (i=1; i<=len; i++){pth[i]=k; len++;for (j=len; j>i+1; j--) pth[j]=pth[j-1];for (j=i+1,s=0; j<=len; j++){pth[j]=k;if (!(s^mp[k]) && dfs(k+1,lmt)) return 1;pth[j]=pth[j+1];s^=bin[pth[j]-1];}len--; pth[i]=pth[i+1];}len--;return 0;}int main(){scanf("%d%d",&n,&m); int i,j,k,x,y,sum=0;for (i=1; i<=m; i++){scanf("%d%d",&x,&y); a[x][y]=a[y][x]=1;}bin[0]=1; lg2[1]=0;for (i=1; i<=n; i++){bin[i]=bin[i-1]<<1; lg2[bin[i]]=i;}for (i=1; i<=n; i++) if (!vis[i]){int head=0,tail=1;h[1]=i; vis[i]=1;while (head<tail){x=h[++head];for (y=1; y<=n; y++)if (a[x][y] && !vis[y]){vis[y]=1; h[++tail]=y;}}for (j=1; j<=tail; j++){mp[j]=0;for (k=1; k<j; k++)if (a[h[j]][h[k]]) mp[j]|=bin[k-1];}len=0;dfs(1,tail);for (j=1; j<=len; j++) ans[++cnt]=h[pth[j]];for (j=1; j<=tail; j++){mp[j]=bin[j-1];for (k=1; k<=tail; k++) if (a[h[j]][h[k]]) mp[j]|=bin[k-1];}int mx=0,tot=bin[tail]-1;memset(f,0,sizeof(f));for (j=tot; j; j--){mx=max(mx,f[j]);for (k=j; k; k^=x){x=k&-k;up(f[j&(tot^mp[lg2[x]+1])],f[j]+1);}}sum+=max(mx,f[0]);}for (i=1; i<=cnt; i++)printf("%d%c",ans[i],(i<cnt)?' ':'\n');printf("%d\n",sum);return 0;}


by lych

2016.5.25

0 0
原创粉丝点击