• hdu6446 网络赛 Tree and Permutation(树形dp求任意两点距离之和)题解


    题意:有一棵n个点的树,点之间用无向边相连。现把这棵树对应一个序列,这个序列任意两点的距离为这两点在树上的距离,显然,这样的序列有n!个,加入这是第i个序列,那么这个序列所提供的贡献值为:第一个点到其他所有点距离之和。求所有序列贡献值之和。

    思路:假如第一个点是k,那么后面n-1个点共有(n - 1)!种排列,也就是说,第一个点是k那么这样的序列的贡献值为(n - 1)!*(k到其他点距离之和),显然最后答案应该是所有点之间的距离和的两倍 *(n - 1)!。问题转化为了求一棵树上所有点之间的距离,怎么求呢?

    假设有一条边E,那么如果要经过E这条边,必然是两个端点在E的两边,假设左边有M点,右边有(n - M)个点,那么一共经过E次数2 *(n - M)* M,所以E的贡献长度为2 *(n - M)* M * E的权值,最后把每条边的贡献长度加在一起就是所有点之间的距离。至于求E两边点数,只要算每个点的子节点数(包括自己)就行了。

    MOD值赋错了wa了一下午...写了两个版本...

    标解:

    参考:HDU2376Average distance(树形dp|树上任意两点距离和的平均值)

    代码:

    /*DP*/
    #include<map>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn = 100000 + 10;
    const int seed = 131;
    const int MOD = 1000000000 + 7;
    const int INF = 0x3f3f3f3f;
    struct Edge{
        ll w;
        int u, v, next;
    }edge[maxn << 1];
    ll fac[maxn], dp[maxn], num[maxn], ans;
    int head[maxn], tot, n;
    void init(){
        fac[0] = 1;
        for(int i = 1; i < maxn; i++){
            fac[i] = (fac[i - 1] * i) % MOD;
        }
    }
    void addEdge(ll u, ll v, ll w){
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    void dfs(int u, int pre){
        num[u] = 1;
        for(int i = head[u]; i != -1; i = edge[i].next){
            int v = edge[i].v;
            ll w = edge[i].w;
            if(v == pre) continue;
            dfs(v, u);
            num[u] += num[v];
            dp[u] = (dp[u] + dp[v] + w * num[v] % MOD * (n - num[v]) % MOD) % MOD;
        }
    }
    int main(){
        init();
        while(~scanf("%d", &n)){
            memset(head, -1, sizeof(head));
            memset(dp, 0, sizeof(dp));
            tot = 0;
            for(int i = 0; i < n - 1; i++){
                ll u, v, w;
                scanf("%lld%lld%lld", &u, &v, &w);
                addEdge(u, v, w);
                addEdge(v, u, w);
            }
            ans = 0;
            dfs(1, -1);
            ans = dp[1] * 2LL % MOD * fac[n - 1] % MOD;
            printf("%lld
    ", ans);
        }
        return 0;
    }
    /*直接代公式*/
    #include<map>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn = 100000 + 10;
    const int seed = 131;
    const int MOD = 1000000000 + 7;
    const int INF = 0x3f3f3f3f;
    struct Edge{
        ll w;
        int u, v, next;
    }edge[maxn << 1];
    ll fac[maxn], ans;
    int head[maxn], family[maxn], tot, n;
    void init(){
        fac[0] = 1;
        for(int i = 1; i < maxn; i++){
            fac[i] = (fac[i - 1] * i) % MOD;
        }
    }
    void addEdge(ll u, ll v, ll w){
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    int dfs(int u, int pre){
        family[u] = 1;
        for(int i = head[u]; i != -1; i = edge[i].next){
            if(edge[i].v == pre) continue;
            family[u] += dfs(edge[i].v, u);
        }
        return family[u];
    }
    int main(){
        init();
        while(~scanf("%d", &n)){
            memset(head, -1, sizeof(head));
            tot = 0;
            for(int i = 0; i < n - 1; i++){
                ll u, v, w;
                scanf("%lld%lld%lld", &u, &v, &w);
                addEdge(u, v, w);
                addEdge(v, u, w);
            }
            ans = 0;
            dfs(1, -1);
            for(int i = 0; i < tot; i += 2){
                ll temp;
                temp = (2LL * family[edge[i].v] * (n - family[edge[i].v])) % MOD;
                temp = (temp * edge[i].w) % MOD;
                temp = (temp * fac[n - 1]) % MOD;
                ans += temp;
                ans %= MOD;
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    viewpager中彻底性动态添加、删除Fragment
    Android仿微信界面--使用Fragment实现(慕课网笔记)
    Android progressBar 自定义
    Android 使用PopupWindow实现弹出菜单
    android手机上安装apk时出现解析包错误的一个解决办法
    设计模式 单例模式
    android 自定义AlertDialog
    android listview异步加载图片
    又优化了一下 Android ListView 异步加载图片
    Hadoop概念学习系列之谈谈RPC(三十三)
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9543927.html
Copyright © 2020-2023  润新知