[题解][luogu p1273]有线电视网

这是一道树形dp......

f[i][j]表示在第i个节点可有j个观众的最大money数(注意可以为负).

转移的话一个一个枚举父亲的最大观众数和儿子节点的最大观众数即可,每个节点的最大观众数可以预处理出来.

最后答案就是f[1][最大的j]>=0,如果全小于0则输出0.

上代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 3010
#define inf 0x7f7f7f7f
using namespace std;
int f[N][N],n,cnt,head[N],m,b[N],son[N];
struct Edge{
    int v,w,nxt;
}E[N<<1];
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    return x*f;
}
void addedge(int u,int v,int w)
{
    E[++cnt].v=v;
    E[cnt].w=w;
    E[cnt].nxt=head[u];
    head[u]=cnt;
}
void dfs1(int u,int fa)//预处理
{
    if(b[u])son[u]=1,f[u][1]=b[u];//son是每个节点的最大观众数
    for(int i=head[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        if(v==fa)continue;
        dfs1(v,u);
        son[u]+=son[v];
    }
}
void dfs(int u,int fa)
{
    for(int i=head[u];i;i=E[i].nxt)
    {
        int v=E[i].v;
        if(v==fa)continue;
        dfs(v,u);
        for(int j=son[u];j>=1;--j)//枚举父亲
            for(int k=son[v];k>=1;--k)//枚举儿子
                f[u][j]=max(f[u][j],f[v][k]+f[u][j-k]-E[i].w);
        for(int j=son[v];j>=1;--j)f[u][j]=max(f[u][j],f[v][j]-E[i].w);
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n-m;++i)
    {
        int k=read(),a,c;
        for(int j=1;j<=k;++j)
        {
            a=read();c=read();
            addedge(i,a,c);addedge(a,i,c);
        }
    }
    for(int i=n-m+1;i<=n;++i)b[i]=read();
    memset(f,-inf,sizeof f);
    dfs1(1,0);dfs(1,0);
    for(int i=son[1];i>=1;--i)if(f[1][i]>=0){printf("%d\n",i);return 0;}
    printf("0\n");
    return 0;
}

 


~~~~

posted @ 2018-07-22 20:50  fanyujun  阅读(140)  评论(0编辑  收藏  举报