【HDU5534 2015长春赛区H】【树上DP转完全背包】Partial Tree 不同度不同权对应最大树权

来源:互联网 发布:卖家淘宝小二在线联系 编辑:程序博客网 时间:2024/05/16 01:47
#include<stdio.h>#include<string.h>#include<ctype.h>#include<math.h>#include<iostream>#include<string>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(x))#define MP(x,y) make_pair(x,y)#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}const int N=0,M=0,Z=1e9+7,ms63=1061109567;int casenum,casei;int n;int a[2020],d[2020];int f[2020];int main(){scanf("%d",&casenum);for(casei=1;casei<=casenum;casei++){scanf("%d",&n);for(int i=1;i<n;i++)scanf("%d",&a[i]);for(int i=1;i<n;i++)d[i-1]=a[i]-a[1];MS(f,0);f[0]=n*a[1];int top=n-2;for(int i=1;i<=top;i++){for(int j=1;j<=i;j++)gmax(f[i],f[i-j]+d[j]);}printf("%d\n",f[top]);}return 0;}/*【trick&&吐槽】做题不应该繁化问题,而应该简化问题。一道题看似很难,其实经过转化可以用简单方法秒杀,尤其是DP。【题意】有T(2015)组数据。每组数据有一个给你n([2,2015])个节点。对于每个节点,如果其度数为x,那么我们能从这个节点上获得a[x]的价值让你把这n个点连成一棵树,问你最终能获得的最大价值【类型】DP【分析】我一开始思考的是树形DP,但这是一个O(n^3)的树形DP,而且难以优化,于是就卡住了。然而我们转变下思维,这道题就可以通过O(n^2)的思路解决了。思维的转变其实很简单,因为题目中的权值是关于度数的,所以我们思考就围绕度数展开。一棵节点数为n的树,拥有的总度数必然是n*2-2。然而这个度数分配是可能出现有的点度数为0,构不成一个树。于是这里采取一个很精妙的操作:把所有点的度初始都设定为1,权值计数为a[1]*n。这样,我们之后只要使得度数之和变成(n+)n-2即可。于是我们用f[i]表示度数为(n+)i条件下的最大收益。那么我们有状态转移方程:f[i]=max(f[i-k]+a[k+1]-a[1]);意思是,我们想要更新度数为i的最大权值,我们会想着它可以基于之前的一个度数,然后把一个未扩展的子节点扩展a[k+1]-a[1]的权值。这样——1,我们有n个点可以扩展度数,而可能扩展的总度数只有n-2,所以一定不会出现多次扩展的情况2,每个点都有一个为1的基准度,一定有办法把它们恰好拼成一棵树。于是这个DP的合法性就得到证明了,从而可以顺利AC这道题。【时间复杂度&&优化】O(n^2)【数据】Sample Input317 8 4 2 0 0 0 0 0 0 0100 99 0 0 0 0 0 0 0 0 02015 9 8 7 6 5 4 3 2 1 0Sample Output9-136*/

1 0
原创粉丝点击