poj1155树形dp+背包

题目大意:每个用户必须连一个发射器,发射的信号从一个点到另一个点需要费用,问电视台在不亏本的情况下最多可以给多少个用户发射信号。

思路:dp[i][j]表示节点i发射j个信号给用户的盈利。注意:dp数组初始化时,dp[i][0] = 0;其余的负无穷,否则会出bug。自己跟着程序走一遍思路会清晰很多。


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>

using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 3005
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define INF 100000000
int n , id , m;
int res[maxn] , tmp[maxn];
struct edge
{
    int u , v , w;
    int next;
}E[maxn];
int head[maxn];
int dp[maxn][maxn];
int val[maxn];

void add(int u , int v , int w)
{
    E[id].u = u;
    E[id].v = v;
    E[id].w = w;
    E[id].next = head[u];
    head[u] = id++;
}

void dfs(int root)
{
    for(int i = head[root] ; i != -1 ; i = E[i].next)
    {
        dfs(E[i].v);
        for(int j = 0 ; j <= res[root] ; j ++) tmp[j] = dp[root][j];
        for(int j = 0 ; j <= res[root] ; j ++)
        {
            for(int k = 1 ; k <= res[E[i].v] ; k ++)
            {
                dp[root][j+k] = max(dp[root][j+k] , tmp[j] + dp[E[i].v][k] - E[i].w);
            }
        }
        res[root] += res[E[i].v];
    }
//    cout << root << ":" << endl;
//    for(int i = 0 ; i <= res[root] ; i ++) cout << dp[root][i] << " ";
//    cout << endl;
}

int main()
{
    while(scanf("%d %d" , &n , &m)!= EOF)
    {
        id = 0;
        mem(head , -1);
        mem(dp , 0);
        for(int i = 1 ;i <= n ; i ++)
        {
            for(int j = 1 ; j <= m ;j ++)
                dp[i][j] = -MOD;
        }
        int v , w , up = n - m , num;
        for(int i = 1 ; i <= up ; i ++)
        {
            scanf("%d" , &num);
            for(int j = 0 ; j < num ; j  ++)
            {
                scanf("%d %d" , &v , &w);
                add(i , v , w);
            }
            res[i] = 0;
        }
        for(int i = up+1 ; i <= n ; i ++) {scanf("%d" , &val[i]) ; dp[i][1] = val[i] ; res[i] = 1;}
        dfs(1);
        for(int i = m ; i >= 0 ; i --)
        {
           // cout << dp[1][i] << endl;
            if(dp[1][i] >= 0)
            {
                printf("%d\n" , i);
                break;
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值