HDOJ树形DP专题之Contestants Division

题目链接

题目大意:给定一棵树,每个结点有一个权值,一棵树的权值为所有结点的权值和,现将这棵树分为两棵子树,要使得两子树的权值差最小。

我的做法是先将无根树化为有根树,然后求每棵子树的权值,最后用一次扫描求结果。需要注意的是结果要用long long型。

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <vector>
 4 #define N 100000
 5 #define MAX(a,b) ((a)>(b)?(a):(b))
 6 #define MIN(a,b) ((a)<(b)?(a):(b))
 7 #define D(a,b) ((a)>(b)?(a)-(b):(b)-(a))
 8 using namespace std;
 9 vector<int> g[N],dep[N];
10 int n,m,a[N],d[N],p[N],dmax;
11 long long sum[N],ans;
12 void make_set()
13 {
14   for(int i=0;i<n;i++)  p[i]=i;
15 }
16 int find_set(int i)
17 {
18   return i==p[i]?p[i]:(p[i]=find_set(p[i]));
19 }
20 void dfs(int u,int fa)
21 {
22   int i,v,l;
23   d[u]=(fa==-1?0:d[fa]+1);
24   dmax=MAX(dmax,d[u]);
25   dep[d[u]].push_back(u);
26   l=g[u].size();
27   for(i=0;i<l;i++)
28   {
29     v=g[u][i];
30     if(v!=fa) dfs(v,p[v]=u);
31   }
32 }
33 void dp()
34 {
35   int i,j,l,v;
36   memset(sum,0,sizeof(sum));
37   for(i=dmax;i>=0;i--)
38   {
39     l=dep[i].size();
40     for(j=0;j<l;j++)
41     {
42       v=dep[i][j];
43       sum[v]+=a[v];
44       if(i>0) sum[p[v]]+=sum[v];
45     }
46   }
47 }
48 int main()
49 {
50   int i,u,v,kase=0;
51   while(scanf("%d%d",&n,&m)&&n)
52   {
53     for(i=0;i<n;i++)  scanf("%d",&a[i]);
54     for(i=0;i<n;i++)  g[i].clear();
55     make_set();
56     for(i=0;i<m;i++)
57     {
58       scanf("%d%d",&u,&v);
59       u--,v--;
60       if(find_set(u)==find_set(v))  continue;
61       p[v]=u;
62       g[u].push_back(v);
63       g[v].push_back(u);
64     }
65     for(i=0;i<n;i++)  dep[i].clear();
66     dmax=0;
67     dfs(0,-1);
68     dp();
69     ans=sum[0];
70     for(i=1;i<n;i++)  ans=MIN(ans,D(sum[i],sum[0]-sum[i]));
71     printf("Case %d: %lld\n",++kase,ans);
72   }
73   return 0;
74 }

 

posted @ 2012-04-27 22:18  BeatLJ  阅读(240)  评论(0编辑  收藏  举报