POJ 3140-Contestants Division(树形dp)

题意:

n给节点的树,分成两个联通分支,使它们大小的绝对值最小,求这个最小值。

分析:

分成两个联通分支,即删除一条边,开始看到m(边数)和n(点数)没什么关系,但题目说的是一棵树,则m==n-1,求出所有的可能的差,取最小值即可

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <complex>
#include <cassert>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
#define lson l,m,rt<<1
#define pi acos(-1.0)
#define rson m+1,r,rt<<11
#define All 1,N,1
#define N 100010
#define read freopen("in.txt", "r", stdin)
const ll  INFll = 0x3f3f3f3f3f3f3f3fLL;
const int INF= 0x7ffffff;
const int mod =  1000000007;
int used[N],head[N],len,n,m;
ll dp[N],num[N],sum;
vector<int>e[N];
/*struct edge{
    int t,next;
}e[N*2];
void add(int a,int b){
    e[len].t=b;
    e[len].next=head[a];
    head[a]=len++;
}*/
ll dfs(int root){
    used[root]=1;
    for(int i=0;i<e[root].size();i++){
        int son=e[root][i];
        if(used[son])continue;
        num[root]+=dfs(son);
        if(sum>=2*num[son])
        dp[root]=min(dp[root],sum-2*num[son]);
        else
        dp[root]=min(dp[root],2*num[son]-sum);
    }
    return num[root];
}
int main()
{
    int tt=0;
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0)break;
        sum=0;
        for(int i=1;i<=n;++i){
            dp[i]=INFll;
            used[i]=0;
            e[i].clear();
            scanf("%I64d",&num[i]);
            sum+=num[i];
        }
        int a,b;
        for(int i=0;i<m;++i){
            scanf("%d%d",&a,&b);
            e[a].push_back(b);
            e[b].push_back(a);
        }
        ll minv;
        if(n==1)
        minv=num[1];
        else{
        dfs(1);
        minv=dp[1];
       for(int i=2;i<=n;++i)
       if(minv>dp[i])
        minv=dp[i];
        }
       printf("Case %d: %I64d\n",++tt,minv);
    }
return 0;
}

 

posted on 2015-08-03 15:02  积跬步、至千里  阅读(195)  评论(0编辑  收藏  举报

导航