1. 程式人生 > >luoguP1273 有線電視網 [樹形dp]

luoguP1273 有線電視網 [樹形dp]

head names 收費 信號 第一個 ron fine clu def

題目描述

某收費有線電視網計劃轉播一場重要的足球比賽。他們的轉播網和用戶終端構成一棵樹狀結構,這棵樹的根結點位於足球比賽的現場,樹葉為各個用戶終端,其他中轉站為該樹的內部節點。

從轉播站到轉播站以及從轉播站到所有用戶終端的信號傳輸費用都是已知的,一場轉播的總費用等於傳輸信號的費用總和。

現在每個用戶都準備了一筆費用想觀看這場精彩的足球比賽,有線電視網有權決定給哪些用戶提供信號而不給哪些用戶提供信號。

寫一個程序找出一個方案使得有線電視網在不虧本的情況下使觀看轉播的用戶盡可能多。

輸入輸出格式

輸入格式:

輸入文件的第一行包含兩個用空格隔開的整數N和M,其中2≤N≤3000,1≤M≤N-1,N為整個有線電視網的結點總數,M為用戶終端的數量。

第一個轉播站即樹的根結點編號為1,其他的轉播站編號為2到N-M,用戶終端編號為N-M+1到N。

接下來的N-M行每行表示—個轉播站的數據,第i+1行表示第i個轉播站的數據,其格式如下:

K A1 C1 A2 C2 … Ak Ck

K表示該轉播站下接K個結點(轉播站或用戶),每個結點對應一對整數A與C,A表示結點編號,C表示從當前轉播站傳輸信號到結點A的費用。最後一行依次表示所有用戶為觀看比賽而準備支付的錢數。

輸出格式:

輸出文件僅一行,包含一個整數,表示上述問題所要求的最大用戶數。

輸入輸出樣例

輸入樣例#1:
5 3
2 2 2 5 3
2 3 2 4 3
3 4 2
輸出樣例#1:
2

說明

樣例解釋

技術分享

如圖所示,共有五個結點。結點①為根結點,即現場直播站,②為一個中轉站,③④⑤為用戶端,共M個,編號從N-M+1到N,他們為觀看比賽分別準備的錢數為3、4、2,從結點①可以傳送信號到結點②,費用為2,也可以傳送信號到結點⑤,費用為3(第二行數據所示),從結點②可以傳輸信號到結點③,費用為2。也可傳輸信號到結點④,費用為3(第三行數據所示),如果要讓所有用戶(③④⑤)都能看上比賽,則信號傳輸的總費用為:

2+3+2+3=10,大於用戶願意支付的總費用3+4+2=9,有線電視網就虧本了,而只讓③④兩個用戶看比賽就不虧本了。


設dp[i][j]為在以i為根的子樹中考慮,選擇了j個葉子節點的最大收益,暴力轉移:

dp[no][j]=max(dp[no][j],dp[no][j-k]+dp[E[e].to][k]-E[e].c)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 #define inf 0x3f3f3f3f
 6 #define dbg(x) cout<<#x<<" = "<<x<<endl
 7 
 8 struct Edge{
 9     int to,nxt,c;
10     Edge(int to=0,int nxt=0,int c=0):
11         to(to),nxt(nxt),c(c){}
12 };
13 
14 const int maxn=3005;
15 
16 int n,n_,m,root=1,cnt=0,ans=0;
17 int head[maxn],dp[maxn][maxn],w[maxn],siz[maxn];
18 Edge E[maxn];
19 
20 inline void a_ed(int from,int to,int c){
21     E[++cnt]=Edge(to,head[from],c);
22     head[from]=cnt;
23 }
24 
25 void dfs(int no){
26     if(no>n_){
27         dp[no][1]=w[no];
28         siz[no]=1;
29         return;
30     }
31     for(int e=head[no];e;e=E[e].nxt){
32         dfs(E[e].to);
33         siz[no]+=siz[E[e].to];
34         for(int j=siz[no];j;j--)
35             for(int k=1;k<=siz[E[e].to];k++)
36                 dp[no][j]=max(dp[no][j],dp[no][j-k]+dp[E[e].to][k]-E[e].c);
37     }
38 }
39 
40 int main(){
41     scanf("%d%d",&n,&m);  n_=n-m;
42     for(int i=1,nu;i<=n_;i++){
43         scanf("%d",&nu);
44         for(int j=0,to,c;j<nu;j++){
45             scanf("%d%d",&to,&c);
46             a_ed(i,to,c);
47         }
48     }
49     for(int i=1;i<=m;i++)  scanf("%d",&w[i+n_]);
50     memset(dp,-inf,sizeof dp);
51     for(int i=1;i<=n;i++)  dp[i][0]=0;
52     dfs(root);
53     for(int i=m;i;i--)
54         if(dp[1][i]>=0){
55             ans=i;
56             break;
57         }
58     printf("%d\n",ans);
59     return 0;
60 }

luoguP1273 有線電視網 [樹形dp]