zoukankan      html  css  js  c++  java
  • Accumulation Degree

    POJ

    题意:有一个有n个节点,n-1条河道的树形水系,每个河道有一个最大容水量c[x][y],源点(树的根节点)可以源源不断出水,树的叶子结点可以无限接纳水,而一个节点水的流量等于流过其儿子节点的水的流量之和,儿子节点水的流量不能超过其与父亲连边的最大容水量,求以哪个点为根(源点)时水流量最大,输出这个最大值即可.(n≤2×10^5)

    首先最朴素的思路是枚举根节点然后跑树形DP,时间复杂度(O(N^2)),只能考虑从根节点下手优化时间复杂度.

    第一次扫描,先任选一个点为根root,跑一次树形DP,预处理出每一个节点的最大流量(size[i]),设y是x的儿子节点,(w[i]=c[x][y])

    如果y的度数为1,(size[x]+=w[i])

    否则,(size[x]+=min(size[y],w[i]))

    第二次扫描,从刚才选定为根的那个节点root出发DFS,DFS的过程中每递归到一个节点,就把该节点作为根节点计算流量,相当于是"换根".设(f[x])表示以x为源点的最大流量.

    显然,(f[root]=size[root])

    假设(f[x])已经求出,对于x的一个子节点y

    如果x的度数为1,(f[y]=size[y]+w[i])

    否则,(f[y]=size[y]+min(f[x]-min(size[y],w[i]),w[i]))

    这里可能有点难理解.其实就是因为这是一棵"无根树",现在x是y的父节点,那么也有可能y是x的父节点,我在第一次扫描中求出了x是y的父节点时的(size[y]),现在我只要求把y当做x的父节点时的流量,然后相加就是(f[y])了.

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    inline int read(){
       int s=0,w=1;char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
       return s*w;
    }
    const int N=200005;
    int ans,in[N],visit[N],size[N],f[N];
    int tot,head[N],nxt[N*2],to[N*2],w[N*2];
    inline void add(int a,int b,int c){
        nxt[++tot]=head[a];head[a]=tot;
        to[tot]=b;w[tot]=c;
    }
    //树形DP预处理出size数组
    inline void dfs1(int x){
        visit[x]=1;size[x]=0;
        for(int i=head[x];i;i=nxt[i]){
    		int y=to[i];
    		if(visit[y])continue;
    		dfs1(y);
    		if(in[y]==1)size[x]+=w[i];
    		else size[x]+=min(size[y],w[i]);
        }
    }
    //DFS计算"换根"后的解
    inline void dfs2(int x){
        visit[x]=1;
        for(int i=head[x];i;i=nxt[i]){
    		int y=to[i];
    		if(visit[y])continue;
    		if(in[x]==1)f[y]=size[y]+w[i];
    		else f[y]=size[y]+min(f[x]-min(size[y],w[i]),w[i]);
    		dfs2(y);
        }
    }
    int main(){
        int T=read();
        while(T--){
    		tot=0;int n=read();
    		for(int i=1;i<=n;i++){
    	    	head[i]=0;in[i]=0;
            	visit[i]=0;size[i]=0;
    		}//多组数据初始化
    		for(int i=1;i<n;i++){
    	    	int a=read(),b=read(),c=read();
    	    	add(a,b,c);add(b,a,c);
    	    	in[a]++;in[b]++;
    		}
    		int root=1;dfs1(root);
    		f[root]=size[root];
    		for(int i=1;i<=n;i++)visit[i]=0;//初始化
    		dfs2(root);ans=0;
    		for(int i=1;i<=n;i++)ans=max(ans,f[i]);
    		printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    云图小助理
    ping包的checksum校验和
    ftp相关
    初始化字符串
    安全的域名解析
    10进制转62进制
    centos6一键安装WordPress
    CEF3编译
    一次性生产KEY
    linux系统问题排查
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10939506.html
Copyright © 2011-2022 走看看