一本通 高手训练 1781 死亡之树 状态压缩dp

Posted chdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一本通 高手训练 1781 死亡之树 状态压缩dp相关的知识,希望对你有一定的参考价值。

LINK:死亡之树

关于去重 还是有讲究的。

题目求本质不同的 具有k个叶子节点的树的个数 不能上矩阵树。

点数很少容易想到装压dp 考虑如何刻画树的形状 发现一个维度做不了 所以。

设状态 f[i][j]表示 点的集合为i叶子集合的点为j的方案树。

这样我们就能知道这棵树大致的样子 空间 为(2^{2n})

当然 如果使用三进制状压 空间复杂度还会进一步降到3^n 不过这道题没有卡空间。

考虑转移 可以枚举点 也可以枚举边。

先考虑枚举边 会出现重复的情况 如先加这条边再加那条边 两条边可以交换。

考虑强制按顺序的话 需要记上次加入的边是什么。时间上过不了。

考虑最后除以(n-1)! 这样也不行因为 这样的话 每次考虑加入边的时候点的状态的刻画存在问题。

考虑枚举点 此时实质还是在加边 还是有重复的。

甚至在某个时刻都有可能出现顺序带来方案数不同的问题。

还是考虑点的有序性 考虑 从一个状态到达另外一个状态转移的唯一性。

可以发现在枚举决策的时候 只有当前决策大于叶子节点的最大的那个再进行转移 此时这样就保证了每一种树都是以唯一的方式构造出来的。

证明 倒着想 考虑当前的一棵树的上一个状态 一定是当前状态减掉最大编号的叶子节点得到的 如果不是 那么上个状态是不能转移到当前状态的。

归纳一下可以得证。

const ll MAXN=11;
ll n,maxx,m,K;
ll sum[1<<MAXN];
ll f[1<<MAXN][1<<MAXN];
ll a[MAXN][MAXN];
signed main()
{
	freopen("dead.in","r",stdin);
    freopen("dead.out","w",stdout);
	get(n);get(m);get(K);
	rep(1,m,i)
	{
		ll get(x);ll get(y);
		a[x][y]=a[y][x]=1;
	}
	rep(2,n,i)if(a[1][i])f[1|(1<<(i-1))][1|(1<<(i-1))]=1;
	maxx=(1<<n)-1;
	rep(1,maxx,i)sum[i]=sum[i>>1]+(i&1);
	rep(1,maxx,i)
	{
		for(ll j=i;j;j=i&(j-1))
		{
			if(!f[i][j])continue;
			for(ll k=1;k<=n;++k)
			{
				if(!(i&(1<<(k-1))))continue;
				ll w=j;
				if(j&((1<<(k-1))))w=w^(1<<(k-1));
				for(ll cc=1;cc<=n;++cc)
				{
					if((1<<(cc-1))<w)continue;
					if(i&(1<<(cc-1)))continue;
					if(!a[k][cc])continue;
					if(sum[w|(1<<(cc-1))]>K)continue;
					f[i|(1<<(cc-1))][w|(1<<(cc-1))]+=f[i][j];
				}
			}
		}
	}
	ll ans=0;
	for(ll j=maxx;j;j=maxx&(j-1))if(sum[j]==K)ans+=f[maxx][j];
	putl(ans);return 0;
}

以上是关于一本通 高手训练 1781 死亡之树 状态压缩dp的主要内容,如果未能解决你的问题,请参考以下文章

信息学奥赛一本通 5.4 状态压缩动态规划

一本通 高手训练 1763 简单树 可持久化线段树 树链刨分 标记永久化

背包问题--(一本通)课后训练

『一本通』区间DP

题解+新技巧--一本通1282:最大子矩阵

一本通 1774:大逃杀