关于本题树上分组背包许多题解在长链时会被卡成n^3级别的问题
查看原帖
关于本题树上分组背包许多题解在长链时会被卡成n^3级别的问题
449265
wind_whisper楼主2021/9/7 10:54

本题树上分组背包的做法还是比较明显的,但是本人初做的时候没有敢这么写...

当时大致估算了下复杂度,背包转移二维,再加节点数,显然是n^3的算法了。。。

当然肯定跑不满,但当时感觉也只是常数问题.

无奈之下抱着也许有降维优化方法的想法去了题解区,发现大致的思路是差不多的。

第一篇题解的一个关键优化是每次u合并儿子son的背包时,两层循环中,外层只循环到u在遍历到son之前的叶节点总数,son只循环到son自己子树内的叶节点总数 ,用刷表法实现。
具体到伪代码上就是

dfs{
	int sum=0,t;
	for(遍历u的儿子son){
		t=dfs(son);
		for(int i->sum)
			for(int j->t) 刷表法更新背包
   		sum+=t;
	}
   return sum;
}	

这么写似乎复杂度就是对的了(虽然我不会证复杂度,但是我卡不掉了...)

后面大部分的题解的优化是类似的,但是有一个很重要的不同:外层循环的遍历次数sum包括了当前儿子的叶节点个数

也就是:

dfs{
	int sum=0,t;
	for(遍历u的儿子son){
		t=dfs(son);
   		sum+=t;
		for(int i->sum)
			for(int j->t) 填表法更新背包
	}
   return sum;
}	

这样应该是为了写填表法方便,但是这样复杂度是假的! 可以构造出一个所有中转站为长链,最后一个中转站向所有用户连出菊花图的数据,在这种数据下,填表法的这种优化没有起效果,还是会被卡到n^3

数据生成器

以下为1-6篇题解在该数据下的表现

1: 0.087s
2: 2.316s
3: 1.545s
4: 2.205s
5: 2.882s
6: 2.004s

而且这已经是在O2的编译环境下了,我试了一篇不开O2,已经到了10s以上。
显然,除了第一篇题解,都无法处理这种情况
建议对这些题解进行修复 @mrsrz
另外,这道题向第一篇题解那么优化的严谨最差复杂度究竟是什么呢?蒟蒻想了很久没有想出来...
希望各位大佬指点迷津awa

2021/9/7 10:54
加载中...