POJ 1155 - TELE 树型DP(泛化背包转移)..

    dp[x][y]代表以x为根的子树..连接了y个终端用户(叶子)..所能获得的最大收益...

    dp[x][ ]可以看成当根为x时..有个背包空间为0~m...每个空间上记录了到到达这个空间的最大收益..

    典型的泛化背包问题... 


Program:

 

#include<iostream>

#include<stdio.h>

#include<string.h>

#include<set>

#include<ctime>

#include<algorithm>

#include<queue>

#include<cmath>

#include<map>

#define oo 100000007

#define ll long long

#define pi acos(-1.0)

#define MAXN 3005

using namespace std;

struct node

{

      int x,y,c,next;

}line[MAXN];

int n,m,_next[MAXN],v[MAXN],dp[MAXN][MAXN],SubNum[MAXN];

void addline(int x,int y,int c,int m)

{

      line[m].next=_next[x],_next[x]=m;

      line[m].x=x,line[m].y=y,line[m].c=c;

      return;

}

void dfs(int x)

{

      int k=_next[x]; 

      SubNum[x]=dp[x][0]=0;

      if (!k) dp[x][1]=v[x],SubNum[x]=1;

      else

      while (k)

      {

            int i,j,y=line[k].y;

            dfs(y);

            SubNum[x]+=SubNum[line[k].y];

            for (i=SubNum[x];i>=1;i--)

               for (j=0;j<=SubNum[y] && j<=i;j++)

                  dp[x][i]=max(dp[x][i],dp[x][i-j]+dp[y][j]+line[k].c); //泛化背包转移

            k=line[k].next;

      }

      return;

}

int main()

{

      int i,num,t; 

      while (~scanf("%d%d",&n,&m))

      {

             num=0;

             memset(_next,0,sizeof(_next));

             memset(dp,-0x1f,sizeof(dp));

             memset(v,0,sizeof(v));

             memset(SubNum,0,sizeof(SubNum));

             for (i=1;i<=n-m;i++)

             {

                   scanf("%d",&t);

                   while (t--)

                   {

                         int A,C;

                         scanf("%d%d",&A,&C);

                         addline(i,A,-C,++num);

                   } 

             }

             for (i=n-m+1;i<=n;i++) scanf("%d",&v[i]);

             dfs(1);

             for (i=m;i>=1;i--)

               if (dp[1][i]>=0) break;

             printf("%d\n",i);

      }

      return 0;

}


 

 

你可能感兴趣的:(poj)