Description
The price of transmission of a signal from one transmitter to another or to the user is given. A price of the entire broadcast is the sum of prices of all individual signal transmissions.
Every user is ready to pay a certain amount of money to watch the match and the TV-network then decides whether or not to provide the user with the signal.
Write a program that will find the maximal number of users able to watch the match so that the TV-network's doesn't lose money from broadcasting the match.
Input
The root of the tree is marked with the number 1, while other transmitters are numbered 2 to N-M and potential users are numbered N-M+1 to N.
The following N-M lines contain data about the transmitters in the following form:
K A1 C1 A2 C2 ... AK CK
Means that a transmitter transmits the signal to K transmitters or users, every one of them described by the pair of numbers A and C, the transmitter or user's number and the cost of transmitting the signal to them.
The last line contains the data about users, containing M integers representing respectively the price every one of them is willing to pay to watch the match.
Output
Sample Input
9 6 3 2 2 3 2 9 3 2 4 2 5 2 3 6 2 7 2 8 2 4 3 3 3 1 1
Sample Output
5
题意:
有一个电视台要用电视网络转播节目。这种电视网络是一树,树的节点为中转站或者用户。树节点的编号为1~N,其中1为总站,2~(N-M)为中转站,(总站和中转站统称为转发站)N-M+1~N为用户,电视节目从一个地方传到另一个地方都要费用,同时每一个用户愿意出相应的钱来付电视节目。现在的问题是,在电视台不亏本的前提下,要你求最多允许有多少个用户可以看到电视节目。
输入:
N M N表示转发站和用户总数,M为用户数
以下N-M行,第i行第一个K,表示转发站i和K个(转发站或用户)相连, 其后第j对数val,cost表示,第i个转发站到val有边,费用cost.
最后一行M个数表示每个用户愿意负的钱。
输出:
不亏本前提下,可以收到节目最多的用户数。
(如果某个用户要收到节目(叶子结点),那么电视台到该用户的路径节点的费用都要付)
分析:
树状dp。由于求的是最多多少用户,那么我们可以把用户个数当成一个状态。dp[i][j]代表i节点为根节点的子树j个用户的时候最大剩余费用。
因为费用可能为负数。所以初始化的时候应该全为-inf. dp[ x ] [ 0 ] = w[ x ]
如果当前点是用户则 dp [ x ][ 1 ] = w[ x ];
如果是中转站 dp [ x ] [ 1 ] = -inf.
然后状态转移和分组背包类似: dp [ x ] [ j ] = max( dp [ x ] [ j ] , dp [ x ][ j - k ] + dp[ son ] [ k ] - cost[ x ][ son ] ).
代码:
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[3010][3010];
int to[3010],fn[3010],nt[3010],cost[3010],tot;
int num[3010];
int w[3010];
int n,m;
void addedge(int u,int v,int c)
{
to[tot] = v;
nt[tot] = fn[u];
cost[tot] = c;
fn[u] = tot++;
}
int dfs(int x)
{
dp[x][0] = w[x];
if(x > n - m)
{
dp[x][1] = w[x];
num[x] = 1;
}
else
{
dp[x][1] = -inf;
num[x] = 0;
}
for(int i = 2 ; i <= m ; i ++)
dp[x][i] = -inf;
for(int i = fn[x] ; i != -1 ; i = nt[i])
{
int y = to[i];
num[x] += dfs(y);
}
for(int i = fn[x] ; i != -1 ; i = nt[i])
{
int y = to[i];
for(int j = num[x] ; j >= 0 ; j --)
{
for(int k = 0 ; k <= num[y] && k <= j ; k ++)
{
dp[x][j] = max(dp[x][j],dp[x][j-k]+dp[y][k]-cost[i]);
}
}
}
return num[x];
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
int num = 0,v,c;
memset(fn,-1,sizeof(fn));
for(int i = 1 ; i <= n - m ; i ++)
{
scanf("%d",&num);
for(int j = 0 ; j < num ; j ++)
{
scanf("%d%d",&v,&c);
addedge(i,v,c);
}
}
memset(w,0,sizeof(w));
for(int i = n - m + 1; i <= n ; i ++)scanf("%d",&w[i]);
memset(dp,0x3f3f3f3f,sizeof(dp));
dfs(1);
int ans = 0;
for(int i = 0 ; i <= m ; i ++)
if(dp[1][i] >= 0) ans = i;
printf("%d\n",ans);
}
return 0;
}