您的位置:首页 > 其它

【ZOJ月赛】【树形DP】【I.Destroy】

2013-01-22 22:30 357 查看
【题目来源】http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=4937

【个人体会】这个题目刚开始看的时候我以为是树的中心点+最小割。但是最小割那边我很怕会超时,因此一开始就没敢打,后来发现可以使用树形DP在O(N)的级别中解决这个问题,因此思路很明确,首先是求树的中心点,然后是树形DP,总级别也是O(N),可能带点常数,但无关紧要。

【题目解析】思路分为两块,第一块是求树的中心点,有经典的O(N)级别的算法。第二块是树形DP,DP[U]表示的是以U为根的子树中,切断所有叶子节点与根节点的联系,所要付出的那个最大边的代价。因此,对于U和U的某个儿子V,在cost[U,V]和DP(V)中选一个小的,记为min{cost[U,V], DP(V)},最后在所有的min{cost[U,V], DP(V)}中选一个max用来更新DP(U)

【代码如下】

#include <iostream>
#include <cstdio>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <deque>
#include <stack>
#include <queue>
#include <algorithm>

#define rep(i, x) for (int i = 1; i <= x; ++i)
#define rept(i, x) for (int i = 0; i < x; ++i)
#define pb push_back
#define ppf pop_front
#define mp make_pair
#define pf push_front
#define x first
#define y second

#define FILE_IO
#define DEBUG

using namespace std;

typedef long long int64;

const int Max = 10001, MAX = 1e16 + 1;

struct edge
{
int v, c, next;
int64 w;
}E[Max * 2];

bool hash[Max];
int N, Cnt, H[Max], Root;
int64 Dp[Max], up[Max], down[Max][3];

void Clear()
{
Cnt = 0;
memset(H, 0, sizeof(H));
memset(up, 0, sizeof(up));
memset(down, 0, sizeof(down));
}

int64 Treedp_Dp(int i)
{
if (Dp[i] != -1) return Dp[i];
int64 t1 = MAX, t2 = 0;
bool flag = false;
for (int j = H[i], v; j; j = E[j].next)
{
v = E[j].v;
if (!hash[v]) hash[v] = flag = true;
else continue;
t1 = min(Treedp_Dp(v), E[j].w), t2 = max(t2, t1);
}
if (!flag) return MAX;
Dp[i] = t2;
return t2;
}

void Treedp()
{
memset(Dp, -1, sizeof(Dp));
memset(hash, 0, sizeof(hash)); hash[Root] = true;
printf("%lld\n", Treedp_Dp(Root));
}

void Center_find()
{
int64 t1 = 0, t2 = MAX;
for (int i = 1; i <= N; ++i)
{
t1 = max(up[i], down[i][1]);
if (t1 < t2) t2 = t1, Root = i;
}
}

void Center_upFind(int u, int fa, int64 dis)
{
if (u != fa)
{
up[u] = up[fa] + dis;
int64 tmp = 0;
if (down[fa][1] == down[u][1] + dis) tmp = down[fa][2] + dis;
else tmp = down[fa][1] + dis;
if (tmp > up[u]) up[u] = tmp;
}
for (int j = H[u], v; j; j = E[j].next)
{
v = E[j].v;
if (hash[v]) continue;
hash[v] = true;
Center_upFind(v, u, E[j].c);
}
}

void Center_downFind(int u)
{
for (int j = H[u], v; j; j = E[j].next)
{
v = E[j].v;
if (hash[v]) continue;
hash[v] = true;
Center_downFind(v);
if (down[v][1] + E[j].c > down[u][1])
{
down[u][2] = down[u][1];
down[u][1] = down[v][1] + E[j].c;
}
else if (down[v][1] + E[j].c > down[u][2]) down[u][2] = down[v][1] + E[j].c;
}
}

void Center()
{
memset(hash, 0, sizeof(hash)); hash[1] = true;
Center_downFind(1);
memset(hash, 0, sizeof(hash)); hash[1] = true;
Center_upFind(1, 1, 0);
Center_find();
}

inline void edgeAdd(int &x, int &y, int &c, int &w)
{
E[++ Cnt].next = H[x], H[x] = Cnt, E[Cnt].v = y, E[Cnt].c = c, E[Cnt].w = w;
}

void Init()
{
for (int i = 1, x, y, c, w; i <= N - 1; ++i)
{
scanf("%d%d%d%d", &x, &y, &c, &w);
edgeAdd(x, y, c, w);
edgeAdd(y, x, c, w);
}
}

int main()
{
#ifdef FILE_IO
//freopen("test.in", "r", stdin);
#endif // FILE_IO
while (scanf("%d", &N) != EOF)
{
Init();
Center();
Treedp();
Clear();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: