POJ 1155 TELE (樹形揹包)

題意

1爲根節點,有m個葉節點,其他爲中間結點,每個結點的權值代表他願意付出的錢,邊的權值代表聯通兩節點的代價,求不虧損的情況下最多能到達多少個葉節點。

思路

另dp[u][i]表示根節點爲u的子樹此時裝了i個葉節點的盈利情況(moneyiEdgecosti )
那麼我們就能得到這樣的狀態轉移方程:
如果u是葉節點dp[u][1]=1
如果u是根節點dp[u][j]=max(dp[u][j],dp[u][jnum]+dp[v][num]costuv ,v是u的兒子節點。

代碼

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define LL long long
#define lowbit(x) ((x)&(-x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1|1
#define MP(a, b) make_pair(a, b)
const int INF = 0x3f3f3f3f;
const int maxn = 1e4 + 7;
const double eps = 1e-8;
const int MOD = 1000000009;
const double PI = acos(-1.0);
vector<pair<int, int> > G[maxn];
int a[maxn], dp[maxn][maxn];
int n, m, tot;
int sum[maxn];

void init(int u, int fa)
{
    sum[u] = 1;
    for (int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i].first;
        if (v != fa)
        {
            init(v, u);
            sum[u] += sum[v];
        }
    }
}

void dfs(int u, int fa, int pre)
{
    dp[u][0] = 0;
    if (G[u].size() == 0)
    {
        dp[u][1] = a[i];
        return ;
    }
    else
    {
        for (int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i].first;
            int w = G[u][i].second;
            if (v != fa)
            {
                dfs(v, u, w);
                for (int j = sum[u]; j >= 1; j--)
                    for (int k = sum[v]; k >= 1; k--)
                        if (j >= k && dp[u][j] != -INF && dp[v][k] != INF)
                            dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k] - w);
            }
        }
    }
}


int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while (scanf("%d%d", &n, &m) != EOF)
    {
        for (int i = 1; i <= n; i++)
            G[i].clear();
        memset(dp, -INF, sizeof(dp));
        for (int i = 1; i <= n - m; i++)
        {
            int u, v, k;
            scanf("%d", &k);
            while (k--)
            {
                scanf("%d%d", &u, &v);
                G[i].push_back(MP(u, v));
                G[u].push_back(MP(i, v));
            }
        }
        for (int i = n - m + 1; i <= n; i++)
            scanf("%d", &a[i]);
        init(1, -1);
        dfs(1, -1, 0);
        for (int i = m; i >= 0; i--)
        {
            if (dp[1][i] >= 0)
            {
                printf("%d\n", i);
                break;
            }
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章