POJ 1155

题意:给定一棵树,树的边带负权,树的叶子带正权,求一棵子树,要求涵盖尽可能多的叶子,同时保证总权值不为负

题解:树形DP,dp[i][j]代表以i为根的子树含有j个叶子结点时最大权值,对每一个i的子树,dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[t][k]-c)

View Code
 1 #include<cstdio>

 2 #include<cstring>

 3 #include<algorithm>

 4 #include<queue>

 5 using namespace std;

 6 const int N=3005,inf=1<<29;

 7 int head[N],nc,n,m,dp[N][N],val[N],num[N];

 8 bool vis[N];

 9 struct Edge

10 {

11     int to,cost,next;

12 } edge[2000000];

13 void add(int a,int b,int c)

14 {

15     edge[nc].to=b;

16     edge[nc].next=head[a];

17     edge[nc].cost=c;

18     head[a]=nc++;

19 }

20 void dfs(int now)

21 {

22     if(head[now]==-1)

23     {

24         if(now>n-m)

25         {

26             num[now]=1;

27             dp[now][0]=0;

28             dp[now][1]=val[now];

29         }

30         else

31         {

32             dp[now][num[now]=0]=0;

33         }

34         return;

35     }

36     else

37     {

38         num[now]=0;

39         dp[now][0]=0;

40         for(int i=head[now]; i!=-1; i=edge[i].next)

41         {

42             int t=edge[i].to,c=edge[i].cost;

43             dfs(t);

44             int tp=num[now]+num[t];

45             for(int j=num[now]+1; j<=tp; j++)

46                 dp[now][j]=-inf;

47             num[now]=tp;

48             tp=num[t];

49             for(int j=num[now]; j>=0; j--)

50             {

51                 for(int k=1; k<=tp&&k<=j; k++)

52                 {

53                     if(dp[now][j-k]!=-inf)

54                         dp[now][j]=max(dp[now][j],dp[now][j-k]+dp[t][k]-c);

55 

56                 }

57             }

58         }

59     }

60 }

61 int main()

62 {

63     //freopen("data.txt","r",stdin);

64     while(scanf("%d%d",&n,&m)!=EOF)

65     {

66         memset(val,0,sizeof(val));

67         memset(head,-1,sizeof(head));

68         nc=0;

69         int nu=n-m;

70         for(int i=1; i<=nu; i++)

71         {

72             int k,a,c;

73             scanf("%d",&k);

74             for(int j=0; j<k; j++)

75             {

76                 scanf("%d%d",&a,&c);

77                 add(i,a,c);

78             }

79         }

80         for(int i=nu+1; i<=n; i++)

81             scanf("%d",&val[i]);

82         memset(dp,0,sizeof(dp));

83         dfs(1);

84         for(int i=num[1]; i>=0; i--)

85         {

86             if(dp[1][i]>=0)

87             {

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

89                 break;

90             }

91         }

92     }

93     return 0;

94 }

你可能感兴趣的:(poj)