poj1155

题意:给定一个树形图,节点数量3000。叶子节点是用户,每个用户如果能看上电视会交一定的电视费。看上电视的条件是从根到该用户的路径全部被修好,修每条边有一个费用。在不亏损(用户交钱总额>=修路总费用)的前提下,最多有多少人能看上电视。

分析:树形dp。dp[u][i][j]表示对于u节点,只看其前i个儿子对应的子树,在这些子树中总共让j个用户看上电视,这样的最大利润是多少(可以为负值)。

那么dp[u][i][j]=max(dp[u][i-1][j], dp[v][num[v][k] + dp[u][i - 1][j - k] - cost(u, v));其中v是u第i个儿子,num[v]表示以v为根的子树中总共有多少用户,cost(u,v)表示u到v这条边需要的花费。

以上是非叶子节点的转移方法,对于叶子节点则稍有不同,直接赋值为该用户交的钱即可。

#include <cstdio>
#include <vector>
using namespace std;

#define D(x) 

const int INF = 0x3f3f3f3f;
const int MAX_N = (int)(3e3) + 10;

int n, m;
int money[MAX_N];
vector<pair<int, int> > edge[MAX_N];
int dp[MAX_N][MAX_N];
int num[MAX_N];
int sum[MAX_N];

void input()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n - m; i++)
    {
        int k;
        scanf("%d", &k);
        for (int j = 0; j < k; j++)
        {
            int a, c;
            scanf("%d%d", &a, &c);
            edge[i].push_back(make_pair(a, c));
        }
    }
    for (int i = n - m + 1; i <= n; i++)
    {
        scanf("%d", &money[i]);
    }
}

void dfs(int u, int cost)
{
    if (u > n - m)
    {
        dp[u][0] = 0;
        num[u] = 1;
        sum[u] = money[u];
        dp[u][1] = money[u];
        return;
    }

    num[u] = 0;
    sum[u] = 0;
    for (int i = 0; i < (int)edge[u].size(); i++)
    {
        int v = edge[u][i].first;
        int w = edge[u][i].second;
        dfs(v, w);
        num[u] += num[v];
        sum[u] += sum[v];
    }
    fill_n(dp[u], num[u] + 1, -INF);
    dp[u][0] = 0;
    for (int i = 0; i < (int)edge[u].size(); i++)
    {
        int v = edge[u][i].first;
        int w = edge[u][i].second;
        for (int j = num[u]; j >= 1; j--)
        {
            int limit = min(j, num[v]);
            for (int k = 1; k <= limit; k++)
            {
                dp[u][j] = max(dp[u][j], dp[v][k] + dp[u][j - k] - w);
            }
        }
    }
}

int main()
{
    input();
    dfs(1, 0);
    int ans = 0;
    for (int i = 0; i <= num[1]; i++)
    {
        if (dp[1][i] >= 0)
            ans = max(ans, i);
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j <= num[i]; j++)
        {
            D(printf("dp[%d][%d]=%d\t", i, j, dp[i][j]));
        }
        D(puts(""));
    }
    printf("%d\n", ans);
    return 0;
}

时间: 2024-10-19 20:19:39

poj1155的相关文章

[POJ1155]TELE

试题描述 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 user

POJ1155 TELE(树形DP)

题目是说给一棵树,叶子结点有负权,边有正权,问最多能选多少个叶子结点,使从叶子到根的权值和小于等于0. 考虑数据规模表示出状态:dp[u][k]表示在u结点为根的子树中选择k个叶子结点的最小权值 最后就从d[1][k]中找满足的最大的k.不过单这样转移时间复杂度是指数级,显然这题就是用树上背包了. 不过其实这题时间复杂度不会算= =反正感觉挺靠谱,交了就AC了.. 又做了一道树上背包,HDU1561和POJ3345. 1 #include<cstdio> 2 #include<cstri

poj1155 树上的背包

题目链接:http://poj.org/problem?id=1155 题意:给定一棵树,1为根结点表示电视台,有m个叶子节点表示客户,有n-m-1个中间节点表示中转站,每条树边有权值.现在要在电视台播放一场比赛,每个客户愿意花费cost[i]的钱观看,而从电视台到每个客户也都有个费用,并且经过一条边只会产生一个费用.问电视台不亏损的情况最多有几个客户可以看到比赛? 思路:在树上的背包,具体看代码注释. 代码: #include<iostream> #include<cstdio>

poj1155:树形dp

题意是:给定一棵树,1为根结点表示电视台,有m个叶子节点表示客户,有n-m-1个中间节点表示中转站,每条树边有权值.然后要是跑叶子节点的话边的值只需要++一次就好,叶子节点有权值.问电视台不亏损的情况最多有几个客户可以看到比赛? 转移方程是   dp[v][j] = max(dp[v][j],dp[v][j-i] + dp[k][i] - len),dp[v][1] = Money[v]. 还是挺直观的吧.感觉还是那样,先dfs出子树的所有情况然后再dp求解就好了.

POJ-1155 TELE (树形DP+分组背包)

题目大意:给一棵带边权的有根树,每个叶子节点有权.边权表示代价,叶子节点的权值代表可以补偿多少代价.问从根节点最多可以到达多少个叶子,使得付出的总代价不大于0. 题目分析:定义状态dp(u,k)表示从u开始到达k个叶子所花费的最小代价.则状态转移方程为: dp(u,k)=min(dp(u,k),dp(son,j)+dp(u,k-j)+u到son的代价). ps:要加上优化,否则超时. 代码如下: # include<iostream> # include<cstdio> # inc

依赖背包变形(经典)——poj1155

这个题用优化后的依赖背包做难以实现,所以用常规的泛化物品的和来做即可 每个节点的容量定义为这个节点下的叶子结点个数,dp[u][j]用来表示节点u下选取j个物品的最大收益,最后从m-0查询dp[1][i],一旦发现是非负数,i则是答案 需要注意的地方:初始化时将所有的dp[i][0]都赋值为0,一个都不选,代价当然是0 dfs遇到u是叶子结点,那么dp[u][1]定义为这个结点的权值,其余状态用-inf来表示不可达 其余状态全部赋初始值为-inf,表示目前不可达 #include<iostrea

【树形dp】TELE

[POJ1155]TELE Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5376   Accepted: 2973 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 o

hdu 1011 树形背包

http://blog.csdn.net/libin56842/article/details/9876503 这道题和poj 1155的区别是: poj1155是边的价值,所以从边的关系入手 hdu1011是点的价值,从点的关系入手,所以node没有val,在dp时不用记录叶子节点个数,只需要对每个点用背包遍历一遍即可 dp[root][j+k] = max(dp[root][j+k],dp[p][k]+dp[root][j]) dp表示在i点放j人能得到的能量 #include <iostr

POJ1155---TELE(树形dp,背包)

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 potenti