版权声明:转就转吧~~记得声明噢~~ https://blog.csdn.net/Soul_97/article/details/83831709
http://poj.org/problem?id=3140
这题不同于删点,这题有删边的思想,不过同样可以转化为删点,暴力找所有点的所有子树节点之和,设初始的时候高校人数总和为s 那么 就找 abs(s-2*子树节点之和)的最小值
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 1e5 + 100;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
ll sum[N],head[N],vis[N];
ll n, m, top,min_,s;
struct edge{
ll v,next;
}e[10*N];
void add(ll a,ll b)
{
e[top].v = b;
e[top].next = head[a];
head[a] = top++;
}
void dfs(int k)
{
vis[k] = 1;
for(int i = head[k];i;i = e[i].next){
int tmp = e[i].v;
if(vis[tmp]) continue;
dfs(tmp);
sum[k] += sum[tmp];
}
//直接找到最小值
ll t = s - 2*sum[k];
if(t < 0)
t *= -1;
min_ = min(min_,t);
}
int main()
{
int static_ = 1;
while(~scanf("%lld%lld",&n,&m),n&&m){
top = 1;
s = 0;
min_ = 1e14;
memset(sum,0,sizeof(sum));
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
for(int i = 1;i <= n;i ++){
scanf("%lld",&sum[i]);
s += sum[i];
}
ll x,y;
for(int i = 1;i <= m;i ++){
scanf("%lld%lld",&x,&y);
add(x,y);
add(y,x);
}
dfs(1);
printf("Case %d: %lld\n",static_++,min_);
}
return 0;
}