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; }