【BZOJ4399】魔法少女LJJ
【BZOJ2555】SubString

【BZOJ4455】【ZJOI2016】小星星

Zarxdy34 posted @ 2016年3月29日 12:53 in BZOJ with tags 状压DP 容斥原理 , 798 阅读

  这题考场上sb写了个状压DP+爆搜,出了考场才反应过来。回去把爆搜改成了状压DP,合并状态,在UOJ上能跑出9个点,BZOJ上刚好能卡过。

  感觉这个做法比较简单就简单地讲一下好了。

  从根节点开始做树形DP,记f[i][j][k]表示树上的编号为i的点,对应原图上编号为j的点,子树(包括这个点)上所有点对应原图上的点的集合为k的方案数,那么从子树到根的状态转移是很显然的。复杂度没仔细地计算过,大概地算了一下还是很理想的。

  直接这么做可能会爆空间,而对于一棵子树,状态数最大是C(n,n/2)级别的,所以存储的时候另开几个数组记录一下状态就好了。

 

#include <ctime>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=17,maxsta=24311;

long long f[maxn][maxn][maxsta];
int vis[maxn][maxn][1<<maxn],sta[maxn][maxn][maxsta],num[maxn][maxn];
long long tempf[maxn][maxsta];
int tvis[maxn][1<<maxn],tsta[maxn][maxsta],tnum[maxn];
int map1[maxn][maxn],map2[maxn][maxn];
int n,m;

void Merge(int x,int xc,int y,int yc)
{
	int xsta,ysta,nsta;
	for (int i=1;i<=num[x][xc];i++)
		for (int j=1;j<=num[y][yc];j++)
			if (!((xsta=sta[x][xc][i])&(ysta=sta[y][yc][j])))
			{
				nsta=xsta|ysta;
				if (!tvis[xc][nsta]) tvis[xc][nsta]=++tnum[xc],tsta[xc][tnum[xc]]=nsta;
				tempf[xc][tvis[xc][nsta]]+=f[x][xc][i]*f[y][yc][j];
			}
}

void DFS(int x,int fa)
{
	for (int i=0;i<n;i++) if (i!=x && i!=fa && map2[x][i]) DFS(i,x);
	for (int i=0;i<n;i++) vis[x][i][1<<i]=1,sta[x][i][1]=1<<i,f[x][i][1]=1,num[x][i]=1;
	for (int j=0;j<n;j++) if (j!=x && j!=fa && map2[x][j])
	{
		memset(tempf,0,sizeof(tempf));
		memset(tvis,0,sizeof(tvis));
		memset(tnum,0,sizeof(tnum));
		for (int i=0;i<n;i++) for (int k=0;k<n;k++) if (i!=k && map1[i][k]) Merge(x,i,j,k);
		memcpy(f[x],tempf,sizeof(tempf));
		memcpy(vis[x],tvis,sizeof(tvis));
		memcpy(sta[x],tsta,sizeof(tsta));
		memcpy(num[x],tnum,sizeof(tnum));
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),--x,--y,map1[x][y]=map1[y][x]=1;
	for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),--x,--y,map2[x][y]=map2[y][x]=1;
	DFS(0,-1);
	long long res=0;
	for (int i=0;i<n;i++) for (int j=1;j<=num[0][i];j++) res+=f[0][i][j];
	printf("%lld\n",res);
	return 0;
}

  

  正解还在看...


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter