poj 1155
树形dp
大意:某电台要广播一场比赛,该电台网络是由N个网点组成的一棵树,其中M个点为客户端,其余点为转发站。客户端i愿支付的钱为pay[i],每一条边需要的花费固定,问电台在保证不亏损的情况下,
最多能使多少个客户端接收到信息?广播台所在的节点编号为1
分析:树形DP
1.user[i].dp[j]表示从转发站i开始计算,满足其子树中j个顾客的最大报酬
分析节点i的孩子节点s
a.放弃该孩子s,值不变
b.取该孩子的若干的节点:user[i].dp[j-k]+user[s].dp[k]-cost[i][j](cost[i][j])为
连通该边所需要付出的代价。
综上:
user[i].dp[j]=max(user[i].dp[j],user[i].dp[j-k]+user[s].dp[k]-cost[i][j]);
2.对于客户端i,user[i].dp[1] = pay[i],即客户端服务一个顾客获得pay[i]的价值
3.最多的服务客服数为user[1].dp[i]中大于0的最大i值,即广播台服务i个客户不亏损
代码:
#include<iostream>
#include<fstream>
using namespace std;
struct e{
int data;
int weight;
e *next;
};
e edge[3010];
int dp[3010][3010];
int weight[3010];
int n,m;
int solve(int s){
int i,j,k,s1,t1;
e *p=edge[s].next;
k=0;j=0;
for(i=1;i<=m;i++)
dp[s][i]=-10000000;
if(!p) {
dp[s][1]=weight[s];
return 1;
}
while(p)
{
j=solve(p->data);
k+=j;
for(s1=k;s1>=1;s1--)
for(t1=0;t1<=j;t1++)
dp[s][s1]=max(dp[s][s1],dp[p->data][t1]+dp[s][s1-t1]-p->weight);
p=p->next;
}
return k;
}
void read(){
// ifstream cin("in.txt");
int i,j,k;
cin>>n>>m;
for(i=1;i<=n-m;i++)
{
cin>>k;
for(j=1;j<=k;j++)
{
e *b=new e;
cin>>b->data>>b->weight;
b->next=edge[i].next;
edge[i].next=b;
}
}
for(i=n-m+1;i<=n;i++)
cin>>weight[i];
solve(1);
for(i=m;i>=0;i--)
if(dp[1][i]>=0)
break;
cout<<i<<endl;
}
int main(){
read();
return 0;
}
浙公网安备 33010602011771号