題意
1爲根節點,有m個葉節點,其他爲中間結點,每個結點的權值代表他願意付出的錢,邊的權值代表聯通兩節點的代價,求不虧損的情況下最多能到達多少個葉節點。
思路
另dp[u][i]表示根節點爲u的子樹此時裝了i個葉節點的盈利情況(
那麼我們就能得到這樣的狀態轉移方程:
如果u是葉節點
如果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;
}