[poj3140]Contestants Division树形dp

题意:切掉树上的某条边,使分开的两棵树上各点的权值和差值最小。

与hdu2196不同的是,此题是点权,其他无太大差别,注意数据范围。

先求出每个节点的子树权值和,然后自底向上dp即可。取$min (abs(sum - 2*dp[u]))$

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<iostream>
 7 using namespace std;
 8 typedef long long ll;
 9 const int maxn=1e6+3;
10 const ll inf=1e17+3;
11 ll head[maxn],tot,n,m,sum;
12 struct edge{
13     ll to;
14     ll nxt;
15     ll w;
16 }e[maxn<<2];
17 void add_edge(int u,int v,int w){
18     e[tot].to=v;
19     e[tot].w=w;
20     e[tot].nxt=head[u];
21     head[u]=tot++;
22 }
23 
24 ll dp[maxn<<2],cnt[maxn<<2];
25 
26 void dfs(ll u,ll fa){
27     for(int i=head[u];i!=-1;i=e[i].nxt){
28         int v=e[i].to;
29         if(v==fa) continue;
30         dfs(v,u);
31         cnt[u]+=1ll*cnt[v];
32     }
33     dp[u]=min(dp[u],sum-2*cnt[u]>=0?sum-2*cnt[u]:2*cnt[u]-sum);
34 }
35 
36 inline int read(){
37     char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
38     int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0';
39     if(k=='-')x=0-x;return x;
40 }
41 
42 int main(){
43     int k=0;
44     while(scanf("%lld%lld",&n,&m)!=EOF&&(n||m)){
45         fill(dp+1,dp+n+1,inf);
46         memset(head,-1,sizeof head);
47         tot=0;
48         sum=0;
49         int a,b;
50         for(int i=1;i<=n;i++){
51             cnt[i]=read();
52             sum+=1ll*cnt[i];
53         }
54         for(int i=0;i<m;i++){
55             a=read();
56             b=read();
57             add_edge(a,b,1);
58             add_edge(b,a,1);
59         }
60         printf("Case %d: ",++k);
61         dfs(1,-1);
62         ll ans=inf;
63         for(int i=1;i<=n;i++){
64             ans=min(ans,dp[i]);
65         }
66         printf("%lld
",ans);
67     }
68     return 0;
69 }
原文地址:https://www.cnblogs.com/elpsycongroo/p/7420336.html