HDOJ树形DP专题之Accumulation Degree

题目链接

题目大意:给定一个流量网络,网络的拓扑结构是无根树,定义A(k)以结点k为源点,其他叶子结点为汇点的最大流量,求的是A(k)的最大值(k=1,2,3……n)。

分析:这题跟树形DP专题Computer那题有点像,那题是距离,这题是流量,本质还是一样。从结点k流出的流量,要么经过儿子结点流出,要么经过父亲结点流出。先DP求每个结点经过儿子结点能流出的最大流量是s[k],在DP求每个结点经过父亲结点能流出的最大流量f[k]。最后结果是MAX(s[k]+f[k]),k=1,2,3...n。

s[k]=sum(MIN(s[i],wik)),i是k的儿子结点且不是叶子结点。s[k]=sum(wik),i是k的儿子结点且是叶子结点。

f[k]=MIN(wik,s[i]-MIN(wik,s[k])+f[i]),i是k的父亲结点且不是叶子结点。f[k]=wik,i是k的父亲结点且是叶子结点。

这题还有一个关键是如何保存结点之间的容量,并且可以根据结点快速访问,最开始我是用并查集求结点k到根结点的容量和(距离),最后超时了。后来用d2p[k]来保存结点k到其父亲结点的容量就AC了。

通过这题的训练,让我进一步理解了“用数组可以搞定一切数据结构”这句话。

View Code
 1 #include <stdio.h>

 2 #include <string.h>

 3 #define N 200001

 4 #define MAX(a,b) ((a)>(b)?(a):(b))

 5 #define MIN(a,b) ((a)<(b)?(a):(b))

 6 int u[2*N],v[2*N],w[2*N],next[2*N],first[N];

 7 int firstd[N],nextd[N];

 8 int p[N],d[N],d2p[N],dmax,n;

 9 long long s[N],f[N],ans;

10 char vis[N];

11 void addEdge(int a,int b,int l,int e)

12 {

13   u[e]=a,v[e]=b,w[e]=l;

14   next[e]=first[a];

15   first[a]=e;

16 }

17 void dfs(int a,int fa)

18 {

19   int e,b;

20   d[a]=(fa==-1?0:d[fa]+1);

21   nextd[a]=firstd[d[a]];

22   firstd[d[a]]=a;

23   dmax=MAX(dmax,d[a]);

24   for(e=first[a];e>=0;e=next[e])

25   {

26     b=v[e];

27     if(b!=fa) dfs(b,p[b]=a),vis[a]++,d2p[b]=w[e];

28   }

29 }

30 void dp1()

31 {

32   int i,a,b,tmp;

33   memset(s,0,sizeof(s));

34   for(i=dmax;i>0;i--)

35   {

36     for(b=firstd[i];b>=0;b=nextd[b])

37     {

38       a=p[b];

39       if(vis[b]==0) tmp=d2p[b];

40       else  tmp=MIN(s[b],d2p[b]);

41       s[a]+=tmp;

42     }

43   }

44 }

45 long long dp(int b)

46 {

47   int a=p[b],tmp;

48   if(f[b]!=-1)  return f[b];

49   if(a==-1) return f[b]=0;

50   if(vis[a]==0) return f[b]=d2p[b];

51   if(vis[b]==0) tmp=d2p[b];

52   else  tmp=MIN(s[b],d2p[b]);

53   return f[b]=MIN(s[a]-tmp+dp(a),d2p[b]);

54 }

55 int main()

56 {

57   int t,i,a,b,l;

58   scanf("%d",&t);

59   while(t--)

60   {

61     scanf("%d",&n);

62     memset(first,-1,sizeof(first));

63     memset(next,-1,sizeof(next));

64     for(i=0;i<n-1;i++)

65     {

66       scanf("%d%d%d",&a,&b,&l),a--,b--;

67       addEdge(a,b,l,2*i);

68       addEdge(b,a,l,2*i+1);

69     }

70     p[0]=-1;

71     dmax=0;

72     memset(vis,0,sizeof(vis));

73     vis[0]=-1;

74     memset(firstd,-1,sizeof(firstd));

75     memset(nextd,-1,sizeof(nextd));

76     dfs(0,-1);

77     dp1();

78     memset(f,-1,sizeof(f));

79     for(i=0;i<n;i++)  dp(i);

80     ans=0;

81     for(i=0;i<n;i++)  ans=MAX(ans,s[i]+f[i]);

82     printf("%lld\n",ans);

83   }

84   return 0;

85 }

 

你可能感兴趣的:(IO)