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