poj3140

版权声明:转就转吧~~记得声明噢~~ 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;
}

猜你喜欢

转载自blog.csdn.net/Soul_97/article/details/83831709