P1273 有線電視網(樹形動規,分組揹包)

2022-06-23 14:03:10 字數 1943 閱讀 6286

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

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

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

寫一個程式找出一個方案使得有線電視網在不虧本的情況下使**轉播的使用者儘可能多。

輸入格式:

輸入檔案的第一行包含兩個用空格隔開的整數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

: 複製53

2225

3232

4334

2輸出樣例#

1: 複製

2

節點與節點之間具有先後的依賴關係,在本題中表現為只有先選擇中轉接點才能訪問到葉子節點。

以題目給定的樣例為例,如果要訪問3,4節點必須先經過2,在這裡假設f[u][j]為節點為u時選擇前j個節點獲得的最大利潤,以f[1][j]來說,他最多可以選擇的節點分別是3,4,5三個節點,但是3,4這兩個節點必須先經過2。那麼f[1][j]可以表示成:$f[1][j]=max(f[1][j],f[1][j-k]+f[son][k]-edge[1][son])$,其中k表示1的前k個節點,edge[1][son]表示節點1和他的孩子之間的邊。這裡可以看成是節點1選擇k個孩子,但這k個孩子是由下一層節點回溯上來的。

每一箇中轉節點相當於一個大的揹包,中轉節點的孩子相當於揹包裡面的商品,如果揹包容量為k,那麼可以在這裡揹包裡面選擇1~k個商品。然後中轉節點在向上層節點回溯,最後匯聚到根節點。

初始化每個節點為負無窮大,最後根據根節點f[1][j]來判斷可以有多少孩子滿足條件。

#includeusing

namespace

std;

#define mp make_pair

#define pb push_backvector

int,int> > ed[3005

];int

n,m;

int v[3005

];int f[3005][3005

];int dfs(int

u)

int sum=0

;

for(auto to:ed[u])} }

return

sum;

}int

main()

} for(int i=n-m+1;i<=n;i++) scanf("

%d",&v[i]);

//memset(f,-0x3f3f3f3f,sizeof(f));

fill(f[0],f[0]+3005*3005,-0x3f3f3f3f

);

for(int i=1;i<=n;i++) f[i][0]=0

;

dfs(1);

for(int j=m;j>0;j--)

}return0;

}