1. 程式人生 > >POJ 1155 TELE 樹形dp + 揹包

POJ 1155 TELE 樹形dp + 揹包

題目連結

題意

一個訊號傳輸網路是樹形的。m個潛在使用者,n-m個訊號發射站。其中1號是電視臺訊號發電站。每個發射站之間連通需要一定的花費。使用者都處在葉子節點處。且每個使用者都會給定量的前補償電視臺。在使電視臺不虧本的情況下,最多可以使多少使用者連同。

思路

樹形dp+分組揹包
用dp[u][j] 表示在u的子樹中連同j個使用者所能獲得的最大價值
如果u是葉子節點dp[u][1] = w[u]
如果是普通結點 dp[u][j] = max(dp[u][j],dp[u][j-k] + d[v][k] - w(u,v) ) , 其中v是u的子節點。

#include<cstdio>
#include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<string> #include<queue> #include<stack> #include<set> #include<map> #define ll long long using namespace std; const int INF = ( 2e9 ) + 2; const ll maxn = 3e3+100; struct
edge { int v,w,next; }e[maxn*2]; int head[maxn]; int tot; int num[maxn],w[maxn]; int dp[maxn][maxn]; // dp[u][j] : 表示在u的子樹中,連線j個客戶可獲得的最大價值 int n,m; void add(int u,int v,int w) { e[tot].v=v; e[tot].w=w; e[tot].next=head[u]; head[u]=tot++; } void dfs(int u,int fa) { for(int i=1
;i<=m;i++) dp[u][i]=-INF; dp[u][0]=0; if(u>=n-m+1) { dp[u][1]=w[u]; return; } for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].v; if(v==fa)continue; dfs(v,u); num[u]+=num[v]; for(int j=num[u];j>=0;j--) for(int k=0;k<=j;k++) dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-e[i].w); } } int main() { while(~scanf("%d%d",&n,&m)) { int k; memset(head,-1,sizeof(head)); tot=0; for(int i=1;i<=n-m;i++) { int v,w; scanf("%d",&k); while(k--) { scanf("%d%d",&v,&w); add(i,v,w); add(v,i,w); } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) dp[i][j]=-INF; for(int i=n-m+1;i<=n;i++) { scanf("%d",&w[i]); num[i]=1; } dfs(1,-1); int ans=0; for(int i=m;i>=1;i--) if(dp[1][i]>=0) { ans=i;break; } printf("%d\n",ans); } }