洛谷 P 1273 有線電視網


題目描述

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

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

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

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

輸入輸出格式

輸入格式:

輸入文件的第一行包含兩個用空格隔開的整數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,有線電視網就虧本了,而只讓③④兩個用戶看比賽就不虧本了。





#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define maxn 3010
int head[maxn],n,m,p,tot,f[maxn][maxn],ans,c[maxn];
struct Edge{
int to,value,next;
}e[maxn*5];
void Add_Edge(int u,int v,int w){
tot++;e[tot].to=v;e[tot].value=w;
e[tot].next=head[u];head[u]=tot;
}
int DFS(int u){
if(u>p){f[u][1]=c[u];return 1;}
//葉節點可以視為只有一個節點(根)的子樹
int s=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to,x=DFS(v);
s+=x;
for(int j=s;j>=1;j--)
for(int k=1;k<=x;k++)
f[u][j]=max(f[u][j],
f[u][j-k]+f[v][k]-e[i].value);
}
return s;
}
int main(){
scanf("%d%d",&n,&m);p=n-m;
for(int i=1;i<=p;i++){
int x,y,z;
scanf("%d",&x);
for(int j=1;j<=x;j++){
scanf("%d%d",&y,&z);
Add_Edge(i,y,z);
}
}
for(int i=p+1;i<=n;i++)
scanf("%d",&c[i]);
memset(f,-127/3,sizeof f );
for(int i=1;i<=n;i++) f[i][0]=0;
DFS(1);

for(int i=1;i<=m;i++)
if(f[1][i]>=0) ans=i;
// 1是根節點 M個居民 枚舉一下...
printf("%d\n",ans);
return 0;
}














注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com