标签:max 子节点 span 背包 color turn stream nbsp cost
题目链接:http://poj.org/problem?id=1155
题意:给定一棵树,1为根结点表示电视台,有m个叶子节点表示客户,有n-m-1个中间节点表示中转站,每条树边有权值。现在要在电视台播放一场比赛,每个客户愿意花费cost[i]的钱观看,而从电视台到每个客户也都有个费用,并且经过一条边只会产生一个费用。问电视台不亏损的情况最多有几个客户可以看到比赛?
思路:在树上的背包,具体看代码注释。
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define ll long long const int maxn=3e3+5; const int INF=0x3f3f3f3f; struct Edge { int v; int w; int next; } edge[maxn<<1]; int dp[maxn][maxn]; int N,M; int head[maxn]; int num[maxn],temp[maxn]; ///num数组是记录以当前节点为根节点的子树最多可以连多少个用户 int I; ///temp数组是为了维护当前状态,防止更新过程状态的变化影响结果 void init() { I=0; memset(head,-1,sizeof(head)); } void addedge(int x,int y,int w) { edge[I].v=y; edge[I].w=w; edge[I].next=head[x]; head[x]=I++; } void dfs(int u) /// 如果dp[0-N][0]=-INF 结果是WA的 { ///这个就是保证跟用户相连的时候第一个就算是负发也要选进来,其他的正数可以弥补。 if(u>N-M) return; ///否则求得的不是最优解 for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; dfs(v); for(int k=0; k<=num[u]; k++) temp[k]=dp[u][k]; for(int j=0; j<=num[u]; j++) for(int k=1; k<=num[v]; k++) dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-edge[i].w); num[u]+=num[v]; } } int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d",&N,&M)==2) { init(); for(int i=0; i<=N; i++) for(int j=1; j<=N; j++) dp[i][j]=-INF;///初始化时候一定要注意! memset(num,0,sizeof(num)); for(int i=1; i<=N-M; i++) { int n; scanf("%d",&n); while(n--) { int a,b; scanf("%d%d",&a,&b); addedge(i,a,b); } } for(int i=N-M+1; i<=N; i++) { scanf("%d",&dp[i][1]); num[i]=1; } dfs(1); for(int i=M; i>=0; i--) { if(dp[1][i]>=0) { printf("%d\n",i); break; } } } return 0; }
标签:max 子节点 span 背包 color turn stream nbsp cost
原文地址:http://www.cnblogs.com/a-clown/p/6107087.html