P1273 有线电视网

P1273 有线电视网 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

令dp[x][i]为第i个节点,转移x个客户的最少费用

转移:dp[x][i]=max(dp[x][i],dp[x][i-k]+dp[v][k]-val[x][v]); 背包树形DP

但是这题获取最重要的便是,树形dp的转移for循环能优化就优化,这即能缩短时间,还能排除一些不符合条件的dp状态

        for(int j=m;j;j--)
            for(int k=1;k<=j;k++)
                dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]-val[x][v]);

例如上面的便会TLE。

就是我们加一个num[x],便是x节点的子树包含了num[x]个客户。

    for(auto v:g[x])
        for(int j=num[x];j;j--)
            for(int k=1;k<=j;k++)
                dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]-val[x][v]);

这样就能大大的优化时间。

Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pb push_back   
#define popb pop_back  
#define fi first
#define se second
const int N=3e3+10;
//const int M=;
const int inf=0x3f3f3f3f;     
//const ll INF=0x3ffffffffffff;
int T,n,m,val[N][N],a[N],dp[N][N],num[N];
vector<int> g[N];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
void dfs(int x)
{
    if(!g[x].size()) dp[x][1]=a[x],num[x]=1;
    for(auto v:g[x])
    {
        dfs(v);
        num[x]+=num[v];
    }
    for(auto v:g[x])
        for(int j=num[x];j;j--)
            for(int k=1;k<=j;k++)
                dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]-val[x][v]);
}
int main()
{
//    freopen("","r",stdin);
//    freopen("","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n-m;i++)
    {
        int k=read();
        for(int j=1;j<=k;j++)
        {
            int u=read();
            val[i][u]=val[u][i]=read();
            g[i].pb(u);
        }
    }
    for(int i=n-m+1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) dp[i][j]=-inf;
    dfs(1);
    int ans=0;
    for(int i=1;i<=m;i++)
        if(dp[1][i]>=0) ans=i;
    printf("%d",ans);
    return 0;
}

 

posted @ 2023-03-12 19:53  QAQ啥也不会  阅读(10)  评论(0编辑  收藏  举报