poj1155 TELE

Description A TV-network plans to broadcast an important football
match. Their network of transmitters and users can be represented as a
tree. The root of the tree is a transmitter that emits the football
match, the leaves of the tree are the potential users and other
vertices in the tree are relays (transmitters). 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 first line of the input file contains two integers N and M,
2 <= N <= 3000, 1 <= M <= N-1, the number of vertices in the tree and
the number of potential users. 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 The first and the only line of the output file should contain
the maximal number of users described in the above text.

树形dp。
如果直接用dp[i][j]表示以i为根的子树花费为j最多得到几个用户,显然空间和时间复杂度都承受不了。
可以改变状态的表示,dp[i][j]表示以i为根的子树取到j个用户的最大收益。枚举子树取到几个用户即可。
注意最后找答案的时候,不能直接找第一个收益为负的,而应该找最后一个收益非负的,因为答案并不具有单调性。

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int dp[3010][3010],size[3010],num[3010],n,m;
vector<int> son[3010],len[3010];
void dfs(int u,int fa)
{
    int i,j,k,v,x;
    dp[u][0]=0;
    for (i=0;i<num[u];i++)
      if (son[u][i]!=fa)
      {
        v=son[u][i];
        x=len[u][i];
        dfs(v,u);
        size[u]+=size[v];
        for (j=size[u];j;j--)
          for (k=1;k<=j&&k<=size[v];k++)
            dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-x);
      }
}
int main()
{
    int i,j,k,p,q,x,y,z,ans;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n-m;i++)
    {
        scanf("%d",&num[i]);
        for (j=1;j<=num[i];j++)
        {
            scanf("%d%d",&x,&y);
            son[i].push_back(x);
            len[i].push_back(y);
        }
    }
    memset(dp,128,sizeof(dp));
    for (i=n-m+1;i<=n;i++)
      scanf("%d",&dp[i][1]),size[i]=1;
    dfs(1,-1);
    for (i=0;i<=m;i++)
      if (dp[1][i]>=0) ans=i;
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值