zoukankan      html  css  js  c++  java
  • 紫书 习题 11-16 UVa 1669(树形dp)

    想了很久, 以为是网络流最大流, 后来建模建不出来, 无奈。

    后来看了 https://blog.csdn.net/hao_zong_yin/article/details/79441180

    感觉思路很巧妙。

    首先题目等价于让每条边经过的次数最多。

    那么假设一条边点a到点b, 假设以b为根节点的子树中的节点数为pb, 那么剩下的

    以b为根节点的子树中的节点数为pa

    我们假设pa > pb

    那么从a这边去b这边, 最多只能走pb次, 因为不能到同一个点,b那边最多就pb个点

    如果经过次数大于pb的话就说明肯定b那边的点至少一个点经过了两次以上

    那么b这边最多去a那边也是pb次, 这次是因为起点就这么多个点。

    所以这条边走过的次数就是pb * 2, 算上权值就是pb * 2 * cost

    那么我们就可以得出, 对于一条边u1, u2, 那么经过这条边的最大权值为

    min(dp[u1], n - dp[u1]) * cost * 2

    dp[u]表示以u为根节点的子树中节点的个数。

    所以我们每条边都加上最大权值即为答案

    最后注意要开 long long。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define REP(i, a, b) for(int i = (a); i < (b); i++)
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 112345;
    struct node { int v, w; }; 
    vector<node> g[MAXN];
    int n, dp[MAXN];
    ll ans;
    
    void dfs(int u, int fa)
    {
    	dp[u] = 1;
    	REP(i, 0, g[u].size())
    	{
    		int v = g[u][i].v, w = g[u][i].w;
    		if(v == fa) continue;
    		dfs(v, u);
    		ans += min(dp[v], n - dp[v]) * w * 2; 
    		dp[u] += dp[v];
    	}
    }
    
    int main()
    {
    	int T, kase = 0;
    	scanf("%d", &T);
    	
    	while(T--)
    	{
    		scanf("%d", &n);
    		REP(i, 0, n) g[i].clear();
    		REP(i, 0, n - 1)
    		{
    			int u, v, w;
    			scanf("%d%d%d", &u, &v, &w);
    			u--; v--;
    			g[u].push_back(node{v, w});
    			g[v].push_back(node{u, w});
    		}
    		
    		ans = 0;
    		dfs(0, -1);
    		printf("Case #%d: %lld
    ", ++kase, ans);
    	}
    	
    	return 0;
    } 



  • 相关阅读:
    Oracle中常见的33个等待事件小结
    DATAGUARD中手工处理日志v$archive_GAP的方法
    ORACLE 如何定位消耗资源的SQL
    ORACLE 全局索引和本地索引
    Oracle中获取执行计划的几种方法分析
    BUFFER CACHE之主要的等待事件
    查看tablespace实际使用量和剩余空间
    Linux环境配置文件的理解
    Shell 传递参数
    Linux开局配置注意事项
  • 原文地址:https://www.cnblogs.com/sugewud/p/9819521.html
Copyright © 2011-2022 走看看