POJ 1155 TELE【树形DP】


POJ 1155 TELE

http://poj.org/problem?id=1155
大意:某电台要广播一场比赛,该电台网络是由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个客户不亏损

View Code
1 #include < stdio.h >
2 #include < string .h >
3   const int N = 3000 + 10 ;
4   const int inf = 999999 ;
5 struct User
6 {
7 int pay; // 若该节点为客户端,记录客户端提供的报酬
8 int dp[N]; // 服务k个顾客的报酬
9 }user[N];
10 int father[N];
11
12 struct Edge
13 {
14 int v;
15 int cost; // 连接该边的花费
16 Edge * next;
17 }edge[N], * index[N];
18
19 bool visited[N];
20 int ednum;
21 inline void addEdge( int from, int to, int cost)
22 {
23 Edge * p = & edge[ednum ++ ];
24 p -> cost = cost;
25 p -> v = to;
26 p -> next = index[from];
27 index[from] = p;
28 }
29 inline int max( int a, int b)
30 {
31 return a > b ? a:b;
32 }
33 int n,m;
34 int dfs( int id)
35 {
36 if (visited[id] == true ) return 0 ;
37 visited[id] = true ;
38 for ( int i = 1 ;i <= n;i ++ )
39 {
40 user[id].dp[i] =- inf;
41 }
42 user[id].dp[ 0 ] = 0 ;
43 if (index[id] == NULL) // 叶子结点
44 {
45 user[id].dp[ 1 ] = user[id].pay;
46 return 1 ; // 一个用户
47 }
48 int userNum = 0 ;
49 for (Edge * p = index[id];p;p = p -> next)
50 {
51 if (visited[p -> v] == false )
52 {
53 int sonuser = dfs(p -> v);
54 userNum += sonuser;
55 for ( int i = userNum;i > 0 ;i -- )
56 for ( int j = 1 ;j <= sonuser;j ++ )
57 {
58 user[id].dp[i] = max(user[id].dp[i],user[id].dp[i - j] + user[p -> v].dp[j] - p -> cost);
59 }
60 }
61 }
62
63 return userNum;
64
65 }
66 int main()
67 {
68
69 while (scanf( " %d%d " , & n, & m) != EOF)
70 {
71 for ( int i = 0 ;i <= n;i ++ )
72 {
73 visited[i] = false ;
74 index[i] = NULL;
75 }
76
77 int mid = n - m,k,a,c;
78 ednum = 0 ;
79 for ( int i = 1 ;i <= mid;i ++ )
80 {
81 scanf( " %d " , & k);
82 while (k -- )
83 {
84 scanf( " %d%d " , & a, & c);
85 addEdge(i,a,c);
86 }
87 user[i].pay = 0 ;
88 }
89
90 for ( int i = mid + 1 ;i <= n;i ++ )
91 scanf( " %d " , & user[i].pay);
92
93 dfs( 1 );
94 for ( int i = m;i >= 0 ;i -- ) // 寻找能使电台不亏损的最大服务顾客数
95 {
96 if (user[ 1 ].dp[i] >= 0 )
97 {
98 printf( " %d\n " ,i);
99 break ;
100 }
101 }
102 }
103 return 0 ;
104 }

树形DP类似的题还有:

pku2342
pku1655
pku3107
pku1463
pku3345

都是不错的题,适合新手入门,O(∩_∩)O~

转载于:https://www.cnblogs.com/AndreMouche/archive/2011/03/26/1996163.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值