zoukankan      html  css  js  c++  java
  • 0x50 动态规划(0x54 树形DP)例题3:积蓄程度(题解)

    题意

    神仙题

    【题目描述】
     有一个树形的水系,由 N-1 条河道和 N 个交叉点组成。
     我们可以把交叉点看作树中的节点,编号为 1~N,河道则看作树中的无向边。
     每条河道都有一个容量,连接 x 与 y 的河道的容量记为 c(x,y)。
     河道中单位时间流过的水量不能超过河道的容量。
     有一个节点是整个水系的发源地,可以源源不断地流出水,我们称之为源点。
     除了源点之外,树中所有度数为 1 的节点都是入海口,可以吸收无限多的水,我们称之为汇点。
     也就是说,水系中的水从源点出发,沿着每条河道,最终流向各个汇点。
     在整个水系稳定时,每条河道中的水都以单位时间固定的水量流向固定的方向。
     除源点和汇点之外,其余各点不贮存水,也就是流入该点的河道水量之和等于从该点流出的河道水量之和。
     整个水系的流量就定义为源点单位时间发出的水量。
     在流量不超过河道容量的前提下,求哪个点作为源点时,整个水系的流量最大,输出这个最大值。  
      【输入格式】
     输入第一行包含整数T,表示共有T组测试数据。
     每组测试数据,第一行包含整数N。
     接下来N-1行,每行包含三个整数x,y,z,表示x,y之间存在河道,且河道容量为z。
     节点编号从1开始。  
      【输出格式】
     每组数据输出一个结果,每个结果占一行。
     数据保证结果不超过2^31−1。  
      【数据范围】
    N≤2*10^5  
      【输入样例】
    1
     5
     1 2 11
     1 4 13
     3 4 5
     4 5 10   
      【输出样例】
    26 
    

    思路

    我的妈呀,如果以前没做仓鼠找sugar II估计我还真做不出这道题目。

    看到这种找根且还带树形DP的题目,脑子里面要马上树立一个正确的价值观,就是我们先固定一个根。

    很明显,我们只要固定了一个根的话,算出他的流量不是手到擒来?

    我们设(f[i])表示这棵子树以(i)为汇点的话,那么流量是多少,随便DP一下就可以算出(f[1]),同时我们又发现,我们貌似是可以(O(1))转移的!

    在这里插入图片描述

    把当树根为(1)的情况转移到树根为(2)的情况貌似只用(O(1)),即减去(2)(1)的贡献,然后把(1)(2)的贡献加到(2),然后我们就可以算出树根为(2)的值了,那么我们再DFS一遍不就可以(O(n))解决了吗?

    当然根节点如果只有一个儿子的话那么转移到儿子后他的(f)(inf)

    #include<cstdio>
    #include<cstring>
    #define  N  210000
    #define  M  410000
    #define  inf  2147483647
    using  namespace  std;
    struct  node
    {
    	int  y,c,next;
    }a[M];int  len,last[N];
    inline  void  ins(int  x,int  y,int  c){len++;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}
    int  f[N]/*表示的是以1为根的话,那么这个点的水流是多少*/,dp[N]/*表示以他为根时的答案。*/;
    int  siz[N],dep[N];
    int  n;
    inline  int  mymin(int  x,int  y){return  x<y?x:y;}
    inline  int  mymax(int  x,int  y){return  x>y?x:y;}
    void  dfs1(int  x,int  fa)
    {
    	siz[x]=1;
    	for(int  k=last[x];k;k=a[k].next)
    	{
    		int  y=a[k].y;
    		if(y!=fa)
    		{
    			dep[y]=dep[x]+1;
    			dfs1(y,x);
    			f[x]+=mymin(f[y],a[k].c);siz[x]+=siz[y];
    		}
    	}
    	if(siz[x]==1)f[x]=inf;
    }
    void  dfs2(int  x,int  fa)//表示以x为根的答案。 
    {
    	dp[x]=f[x];//索性继承 
    	for(int  k=last[x];k;k=a[k].next)
    	{
    		int  y=a[k].y;
    		if(y!=fa)
    		{
    			int  now=f[x];
    			if(siz[x]-siz[y]==1  &&  dep[x]==0/*在根节点*/)f[x]=inf;
    			else  f[x]-=mymin(f[y],a[k].c);
    			if(siz[y]==1)f[y]=mymin(f[x],a[k].c);//特判这个点是不是叶子节点 
    			else  f[y]+=mymin(f[x],a[k].c);
    			dfs2(y,x);
    			if(siz[y]==1)f[y]=inf;
    			else  f[y]-=mymin(f[x],a[k].c);
    			f[x]=now;
    		}
    	}
    }
    int  main()
    {
    	int  T;scanf("%d",&T);
    	while(T--)
    	{
    		len=0;memset(last,0,sizeof(last));
    		memset(f,0,sizeof(f));
    		memset(dp,0,sizeof(dp));//暴力初始化
    		scanf("%d",&n);
    		for(int  i=1;i<n;i++)
    		{
    			int  x,y,z;scanf("%d%d%d",&x,&y,&z);
    			ins(x,y,z);ins(y,x,z);
    		}
    		dfs1(1,0);
    		dfs2(1,0);
    		int  ans=0;
    		for(int  i=1;i<=n;i++)ans=mymax(dp[i],ans);
    		printf("%d
    ",ans);
    	}
    	return  0;
    }
    
  • 相关阅读:
    react脚手架搭建及配置
    mac使用技巧
    nginx配置
    vue常见前端UI库
    自定义指令
    代码缩进修改
    webpack学习入门
    webpack使用extract-text-webpack-plugin打包时提示错误
    webpack未成功全局安装
    基于jQuery的AJAX实现三级联动菜单
  • 原文地址:https://www.cnblogs.com/zhangjianjunab/p/11714515.html
Copyright © 2011-2022 走看看