有线电视网(树形dp)

有线电视网

某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和。现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号。写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多。2≤N≤3000。

关于树形dp,有一个经典套路,就是n^3动归,从下到上枚举每个点,每个点下的孩子和一个值。这道题也不例外。设计状态\(dp[k][i][j]\)为,对于第i个点,用前k个儿子,满足j个客户的最大收益。于是状态转移方程就是:\(dp[k][i][j]=max(dp[k-1][i][p]+dp[k][i][j-p]\ (0\le p\le j)\)。观察一下这个状态和方程,它是一个多决策最优化问题,满足最优化原理,且无后效性。同时k是可以被滚动数组压缩的,从后往前循环枚举p即可。

#include <cstdio>
using namespace std;

const int maxn=3005, maxm=3005, INF=1e9;

struct Graph{
    struct Edge{
        int to, next, v; Graph *bel;
        inline int operator *(){ return to; }
        Edge& operator ++(){
            return *this=bel->edge[next]; }
    };
    void addedge(int x, int y, int v){
        Edge &e=edge[++cntedge];
        e.to=y; e.next=fir[x]; e.v=v;
        e.bel=this; fir[x]=cntedge;
    }
    Edge& getlink(int x){
        return edge[fir[x]]; }
    Edge edge[maxm*2];
    int cntedge, fir[maxn];
}g;

int n, m, size[maxn];
int dp[maxn][maxn];

inline int max(int x, int y){
    return x<y?y:x; }
void predfs(int now, int par){
    Graph::Edge e=g.getlink(now);
    for (; *e; ++e){
        if (*e==par) continue;
        predfs(*e, now);
        size[now]+=size[*e];
    }
    if (size[now]==0) size[now]=1;
}

void dfs(int now, int par){
    Graph::Edge e=g.getlink(now);
    dp[now][0]=0; int cntsize=0;
    for (; *e; ++e){  //枚举孩子
        if (*e==par) continue; dfs(*e, now);
        cntsize+=size[*e];
        for (int j=cntsize; j>=0; --j)  //总客户数
        for (int p=cntsize-size[*e]; p>=0; --p)  //前面的孩子中有几个客户
            dp[now][j]=max(dp[now][j],
                dp[now][p]+dp[*e][j-p]-((j-p)?e.v:0));
    }
}

void init(){
    for (int i=0; i<maxn; ++i)
        for (int j=0; j<maxn; ++j)
            dp[i][j]=-INF;
}

int main(){
    init();
    scanf("%d%d", &n, &m); int k, a, c;
    for (int i=1; i<=n-m; ++i){
        scanf("%d", &k);
        for (int j=1; j<=k; ++j){
            scanf("%d%d", &a, &c);
            g.addedge(i, a, c);
        }
    }
    for (int i=n-m+1; i<=n; ++i) scanf("%d", &dp[i][1]);
    predfs(1, 0); dfs(1, 0); int pos;
    for (pos=size[1]; pos>=0; --pos)
        if (dp[1][pos]>=0) break;
    printf("%d", pos); return 0;
}

原文地址:https://www.cnblogs.com/MyNameIsPc/p/8427581.html

时间: 2024-10-07 05:42:19

有线电视网(树形dp)的相关文章

luoguP1273 有线电视网 [树形dp]

题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和. 现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号. 写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多. 输入输出格式 输

Luogu P1273 有线电视网(树形dp+背包)

题面 题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和. 现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号. 写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多. 输入输出格

[P1273] 有线电视网 (树形DP+分组背包)

题意:给出一棵树,有边权,只有叶子节点有点权,求一个合法方案(选择走到哪几个叶子节点,且路径上的权值和 <= 要走到的叶子节点的点权和),使得选择的叶子节点数量尽量的多: 解法:树形DP+分组背包: 1.树形DP:这是一棵树,所以叫树形DP: 2.分组背包:在这里主要是运用到了它的思想:我们可以设 f[i][j],表示 i节点选择了 j个叶子节点的费用最大值:假设现在在 x节点,它的下面有 n个叶子节点(不是它的儿子),那么我们就要处理出它选 1,2,3,……,n 个叶子节点的情况,但是由于这是

洛谷 P1273 有线电视网(dp)

/* 想了半天没想出状态 自己还是太弱了 QAQ 题目问的是最多供给多少户 一般想法是把这个值定义为状态量 没想出来QAQ....看了看题解的状态 很机智.... f[i][j]表示i的子树 选了j个叶子的最大收益 这样 不亏本就是收益>=0 转移的话 先搜一下这个子树有几个叶子 然后枚举儿子 枚举当前儿子分几个叶子 这里的枚举顺序有套路 从大到小枚举i分几个 从小到大枚举j分几个 这样可以避免 重复选择 注意初始化 */ #include<iostream> #include<c

树形dp小结

做了好久的树形DP(大雾) ,(noip)csp-s考了好多树形DP 树形DP基本分为这几种 1.最大独立集(没有上司的舞会) 经典树形DP \(dp[i][0/1]\) 表示i这个点选与不选. \(dp[u][0] += dp[v][1];\) \(dp[u][1] += max(dp[v][0],dp[v][1]);\) 2.最小点覆盖(战略游戏) 状态与上面一样 \(dp[u][0] += dp[v][1];\) \(dp[u][1] += min(dp[v][0],dp[v][1]);\

有线电视网(luogu 1273)树形DP

题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和. 现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号. 写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多. 输入输出格式 输

luogu P1273 有线电视网

题目链接 luogu P1273 有线电视网 题解 树形背包 dp[i][j]表示在以i为根的子树中,满足j个客户的需求所能获得的最大收益 代码 #include<cstdio> #include<algorithm> #include<cstring> const int maxn = 3007; //using namespace std; inline int read() { int x = 0,f = 1; char c = getchar(); while(

[DP总结]树形DP

树形DP 树形DP,顾名思义,是在树上进行DP操作,因此往往需要使用DP实现,在转移时,通常先递归求出子树中的解,再在根节点进行计算转移. 树中只有两种关系,一种是父子关系,一种是平行关系. 下面是几道简单的树形DP.从中我们可以窥出树形DP的本质. [luogu] P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是

洛谷1273 有线电视网

本题地址:http://www.luogu.org/problem/show?pid=1273 题目描述 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和.     现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供