hdu 5534

题目描述:n个节点度数之和为n-2,每个节点预分配了1个度,任意分配度数是否有可能形成树?

从1到n节点,考虑树的形状,考虑分配给当前节点i的度数,并且注意到当前节点的度数不会影响其他节点(之前或者之后),因为之前先给每个节点分配1度的度数,然后n个节点度数之和确定,从1到n考虑,每个节点都有分配到0到n-2的度数的可能,还有n个节点的度数之和的为n-2的限制(某个节点分配到0个度,说明是叶子)。

求在y1+y2+.....+y[n-2]=(n-2)的条件下,F[y1]+F[y2]+.....F[y[n-2]]的最大收益;

其中xi代表i度的有几个,f[i]代表i度的收益;

将n-2个度分为n份,可以想象一条长度为n-2的线段,切成n段,获得的收益为F[len],求收益最大?每段的长度的取值范围为0到n-2,那么可以这样考虑,最优情况下,一厘米长度的有几个?2厘米长度的有几个?3厘米长度的有几个?......n-2厘米长度的有几个?

数学形式为在x1+x2+....+x[n-2]=(n-2)的条件下,求x1*f[1]+x2*f[x2]+...x[n-2]*f[n-2]的最大值?

其次还需处理线段长度合并时权值的变化,消除的思想。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 2200
#define inf 0x3f3f3f3f3f3f
using namespace std;
int T,n,f[maxn];  //f代表石子的重量
int d[maxn];
int f1;
void init()
{
    for(int i=1;i<maxn;i++)
        d[i]=-inf;
    d[0]=0;
}
void solve() //可以理解成切线段
{
    int ans=n*f1;
    for(int i=1;i<=n-2;i++)  //度数为i的有多少个
    {
       for(int j=i;j<=n-2;j++)
       {
              if(d[j-i]+f[i] > d[j] )
               {
                   d[j]=d[j-i]+f[i];
               }
       }
    }
    ans+=d[n-2];
     printf("%d
",ans);
}

int main()
{
   // freopen("test.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
       scanf("%d",&n);
       scanf("%d",&f1);
       for(int i=1;i<=n-2;i++)
       {
           scanf("%d",&f[i]);
           f[i]-=f1;
       }
       init();
       solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xianbin7/p/4989520.html