题目链接:http://poj.org/problem?id=3140
题意:给你一棵树,每个点都有点权,求出去掉一条边后剩余两子树的最小权值之差
思路:dp[u]代表以u点为根的子树的权值和,这样当去掉u和u的父节点间的那条边时,其权值差即为(总权值 - dp[u]) - dp[u] 的绝对值,注意这题的数据范围需要用long long,而且ans初始值要给的足够大
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <functional>
#include <utility>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <set>
#include <cmath>
#include <stdlib.h>
#include <climits>
#pragma comment (linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = 100010;
const int inf = 0x3f3f3f3f;
typedef long long ll;
int n, m, cnt;
int head[maxn];
ll dp[maxn], val[maxn], sum, ans;
ll Abs(ll a)
{
return a > 0 ? a : -a;
}
struct edge
{
int to, nxt;
} e[maxn * 2];
void init()
{
sum = 0;
cnt = 0;
ans = 1e18;
memset(head, -1, sizeof(head));
memset(dp, 0, sizeof(dp));
}
void add(int u, int v)
{
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
ll dfs(int u, int fa)
{
dp[u] = val[u];
for (int i = head[u]; ~i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa) continue;
dp[u] += dfs(v, u);
}
ans = min(ans, Abs(sum - dp[u] - dp[u]));
return dp[u];
}
int main()
{
int ca = 1;
while (~scanf("%d%d", &n, &m) && (n + m))
{
init();
for (int i = 1; i <= n; i++)
{
scanf("%I64d", &val[i]);
sum += val[i];
}
for (int i = 1; i <= m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
dfs(1, -1);
printf("Case %d: %I64d\n", ca++, ans);
}
return 0;
}