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;
}

posted on 2011-05-10 13:15  宇宙吾心  阅读(983)  评论(1)    收藏  举报

导航