bzoj 3149: [Ctsc2013]复原 dfs

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

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

       最大独立集的话子集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

你可能感兴趣的:(动态规划,DFS,子集Dp)