题意:
给你一棵树,每个结点都有一个权值,要你求删除一条边之后,分成的两棵树的权值之差最小
分析:
从1开始深度优先遍历,用best 记录最优值初始化为最大,数据超过int所以用long long,用cnt[i]表示以i为结点的树的权值和,比较total - cnt[i] >= cnt[i],更新best,遍历所有结点一遍即得到最优值~
//AC CODE:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 100010;
int n, m, k, u, v;
int per[N];
ll total, best;
ll cnt[N];
bool vis[N];
vector<int> adj[N];
ll dfs(int t)
{
cnt[t] = per[t];
vis[t] = true;
int len=adj[t].size();
for (int i = 0; i < len; ++i)
{
int u= adj[t][i];//子结点
if (vis[u])
continue;
cnt[u] = dfs(u);//深度优先遍历
cnt[t] += cnt[u];
ll res;
if (total - cnt[u] >= cnt[u])
res = total - 2 * cnt[u];
else
res = 2 * cnt[u] - total;
if (res < best)
best = res;
}
return cnt[t];
}
int main()
{
int t = 1;
while (scanf("%d%d", &n, &m), n || m)
{
total = 0;
//best=9223372036854775807LL;//64位最大值
best=0x7fffffffffffffffLL;//64位最大值
for (int i = 1; i <= n; ++i)
{
scanf("%d", &per[i]);
total += per[i];
adj[i].clear();
cnt[i] = 0;
vis[i] = false;
}
for (int i = 1; i <= m; ++i)
{
scanf("%d%d", &u, &v);
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs(1);
printf("Case %d: %I64d\n", t++, best);
}
return 0;
}