您的位置:首页 > 产品设计 > UI/UE

POJ 1947 Rebuilding Roads

2013-11-23 23:00 375 查看
题意:给一棵含有n个节点的树,问最少切割多少条边,能够得到一棵恰好包含p个节点的子树。

解法:设d[x][i]表示以x为根的子树,切割出含有i个节点的子树最少需要切割多少条边。对于每个子节点y,可以直接将其切掉,也可以对以y为根的树进行切割,然后给以x为根的树增加节点数。这个地方其实就是一个背包,好好体会。

   状态转移方程为d[x][i] = max(d[x][i]+1, d[x][i-j] + d[y][j])。

   注意枚举的时候要逆序,否则要多开一维数组。

tag:树形dp, 背包

/*
* Author:  Plumrain
* Created Time:  2013-11-19 16:11
* File Name: DP-POJ-1947-2.cpp
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

#define CLR(x) memset(x, 0, sizeof(x))
#define PB push_back
const int maxint = 2147483647 / 10;

int n, p, f;
int d[200][200];
bool vis[200];
vector<int> son[200];

void init()
{
for (int i = 1; i <= n; ++ i)
son[i].clear();

CLR (vis);
int t1, t2;
for (int i = 0; i < n-1; ++ i){
scanf ("%d%d", &t1, &t2);
vis[t2] = 1;
son[t1].PB (t2);
}

for (int i = 1; i <= n; ++ i)
if (!vis[i]){
f = i; break;
}
}

void dfs(int x)
{
int sz = son[x].size();
for (int i = 1; i <= p; ++ i)
d[x][i] = maxint;
d[x][1] = 0;

for (int t = 0; t < sz; ++ t){
int v = son[x][t];
dfs(v);
for (int i = p; i >= 1; -- i){
d[x][i] += 1;
for (int j = 1; j < i; ++ j)
d[x][i] = min(d[x][i], d[x][i-j] + d[v][j]);
}
}
}

int main()
{
while (scanf ("%d%d", &n, &p) != EOF){
init();

dfs(f);

d[f][p] -= 1;
int ans = maxint;
for (int i = 1; i <= n; ++ i)
ans = min(ans, d[i][p]);
printf ("%d\n", ans + 1);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: