虽然表算是神奇的分组但是只要搜搜搜就过去了。。。
每个连通块分别考虑,然后枚举这一条弦的两个端点;如果一个端点已经确定,那么另一个端点的范围必然是一个区间,用位运算加速即可。然后就过了。。。
最大独立集的话子集dp一下就好了。。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #define N 25 #define M 1300005 using 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