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 constint N =3000+10;
4 constint 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)return0;
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 return1;//一个用户
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 return0;
104 }
2 #include<string.h>
3 constint N =3000+10;
4 constint 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)return0;
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 return1;//一个用户
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 return0;
104 }
树形DP类似的题还有:
pku2342 |
pku1655 |
pku3107 |
pku1463 |
pku3345 |
都是不错的题,适合新手入门,O(∩_∩)O~