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 }

 

你可能感兴趣的:(visio)