POJ - 1155 TELE (树形dp+背包)

题目链接点击打开链接

题意:给定一棵树,1为根结点表示电视台,有m个叶子节点表示客户,有n-m-1个中间节点表示中转站,每条树边有权值。现在要在电视台播放一场比赛,每个客户愿意花费cost[i]的钱观看,而从电视台到每个客户也都有个费用,并且经过一条边只会产生一个费用。问电视台不亏损的情况最多有几个客户可以看到比赛?

我把边权放到相连的子节点当变成点权存负值,dp[i][j]表示i这个节点要j个叶子节点的最大收益

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=3e3+10;
int dp[maxn][maxn],val[maxn],tmp[maxn],cost[maxn];
vector<int>a[maxn];
int siz[maxn];
void dfs(int u,int fa)
{
    if(a[u].size()==0)
    {
        siz[u]=1;
        dp[u][1]=val[u];
    }
    dp[u][0]=0;
    for(int i=0;i<a[u].size();i++)
    {
        int v=a[u][i];
        if(v==fa) continue;
        dfs(v,u);
        memset(tmp,-0x3f,sizeof tmp);
        for(int j=0;j<=siz[u];j++)
        {
            for(int k=0;k<=siz[v];k++)
            {
                int tm=cost[v];
                if(k==0) tm=0;
                tmp[j+k]=max(dp[u][j]+dp[v][k]+tm,tmp[j+k]);///转移方程1
            }
        }
        siz[u]+=siz[v];
        dp[u][0]=0;
        for(int j=1;j<=siz[u];j++)
            dp[u][j]=max(dp[u][j],tmp[j]);///转移方程2
    }
}
int n,m;
int main()
{
    ///freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        memset(dp,-0x3f,sizeof dp);
        memset(siz,0,sizeof siz);
        for(int i=0;i<=n;i++) a[i].clear();
        for(int i=1;i<=n-m;i++)
        {
            int x,k,y;
            scanf("%d",&k);
            while(k--)
            {
                scanf("%d%d",&x,&y);
                cost[x]=-y;///转换成负点权
                a[i].push_back(x);
            }
        }
        for(int i=n-m+1;i<=n;i++)
            scanf("%d",&val[i]);

        dfs(1,-1);
        for(int i=m;i>=0;i--)
        if(dp[1][i]>=0)
        {
            printf("%d\n",i);
            break;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dllpxfire/article/details/81060595
今日推荐