POJ 1155 TELE(二分+树DP)
题意:一个电视网络要转播一场比赛,电视网络的拓扑结构是一棵树,树根是总站,叶子结点都是用户,树边权为信号通过此边的费用,转播总费用为信号通过的所有边的权和,现已知每个用户愿意交付的费用,问电视台在不亏本的情况下最多能为多少用户转播比赛。
分析:定义dp[i][j]为从结点 i 往下给 j 个用户转播比赛的最大利润,最后的答案就是使 dp[1][j] 非负的最大的j,可以二分求解。
dfs里面那个 j 循环需要根据叶子结点的数目进行优化,否则会TLE
View Code
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 3001 #define INF 0xc3c3c3c3 int n,m,e,val[N]; int first[N],next[N],v[N],w[N]; int dp[N][N]; void init() { e=0; memset(first+1,-1,sizeof(first[0])*n); } void add(int a,int b,int c) { v[e]=b; w[e]=c; next[e]=first[a]; first[a]=e++; } int dfs(int a) { int i,b,cnt=0; memset(dp[a]+1,0xc3,sizeof(dp[0][0])*m); dp[a][0]=0; if(first[a]==-1) { dp[a][1]=val[a]; return 1; } for(i=first[a];~i;i=next[i]) { b=v[i]; cnt+=dfs(b); for(int j=min(cnt,m);j;j--) { for(int k=1;k<=j;k++) if(dp[a][j-k]!=INF&&dp[b][k]!=INF) { dp[a][j]=max(dp[a][j],dp[a][j-k]+dp[b][k]-w[i]); } } } return cnt; } int main() { int a,b,c,k; while(~scanf("%d%d",&n,&m)) { init(); for(a=1;a<=n-m;a++) { scanf("%d",&k); while(k--) { scanf("%d%d",&b,&c); add(a,b,c); } } for(;a<=n;a++) scanf("%d",&val[a]); dfs(1); a=0,b=m+1; while(a+1<b) { c=a+b>>1; if(dp[1][c]<0) b=c; else a=c; } printf("%d\n",a); } return 0; }