zoukankan      html  css  js  c++  java
  • 图转树 最小生成树 树形dp[2020 Multi-University Training Contest 6 A Very Easy Graph Problem ]

    图转树 最小生成树 树形dp2020 Multi-University Training Contest 6 A Very Easy Graph Problem

    题目大意:

    一张 m 大小的图,每一个节点被标记为0或者1,第 (i) 条边的大小是 (2^i) ,问是否任意两个01点对之间的最短路的距离和。

    题解:

    注意这个边的大小是 (2^i) ,对于 (2^i>2^1+2^2+2^3+...2^{i-1}) 所以优先考虑前面的边,如果前面的边可以保证联通,则前面的边一定更优,所以把这个图转化成一棵树,然后树形dp即可。

    之前联想杯有一个类似的题目:https://acm.ecnu.edu.cn/contest/270/problem/D/

    #include <bits/stdc++.h>
    #define debug(x) cout<<"debug:"<<#x<<" = "<<x<<endl;
    using namespace std;
    typedef long long ll;
    const int maxn = 2e5+10;
    const int mod = 1e9+7;
    int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt,f[maxn],have[maxn],num,n,m,siz[maxn];
    ll w[maxn<<1],p[maxn];
    void Init(){
        p[0] = 1;
        for(int i=1;i<maxn;i++) p[i]=p[i-1]*2%mod;
    }
    void init(int n){
        cnt = 0;
        for(int i=0;i<=n;i++) head[i] = 0,f[i] = i,have[i] = 0;
    }
    void add(int u,int v,int i){
        ++cnt,to[cnt]=v,nxt[cnt]=head[u],w[cnt]=p[i],head[u]=cnt;
        ++cnt,to[cnt]=u,nxt[cnt]=head[v],w[cnt]=p[i],head[v]=cnt;
    }
    int Find(int x) {
        return x == f[x] ? x : f[x] = Find(f[x]);
    }
    void unite(int x,int y){
        x = Find(x);
        y = Find(y);
        if(x==y) return ;
        f[x] = y;
    }
    bool same(int x,int y){
        return Find(x)==Find(y);
    }
    ll dp[maxn];
    void dfs(int u,int pre) {
    //    printf("u=%d pre=%d
    ",u,pre);
        dp[u] = 0, siz[u] = 1;
        for (int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if (v == pre) continue;
            dfs(v, u);
            have[u] += have[v];
            siz[u] += siz[v];
            ll blackIn = have[v], blackOut = num - blackIn;
            ll whiteIn = siz[v] - have[v], whiteOut = n - num - whiteIn;
    //        printf("u=%d v=%d
    ",u,v);
            dp[u] = ((dp[u] + dp[v]) % mod + (blackIn * whiteOut + whiteIn * blackOut) % mod * w[i] % mod) % mod;
        }
    }
    
    int main() {
        Init();
        int T;
        scanf("%d", &T);
        while (T--) {
            scanf("%d%d", &n, &m);
            init(n),num = 0;
            for(int i=1;i<=n;i++) scanf("%d",&have[i]),num += have[i];
            for (int i = 1; i <= m; i++) {
                int u, v;
                scanf("%d%d", &u, &v);
                if (same(u, v)) continue;
                unite(u, v);
                add(u, v, i);
            }
            dfs(1,0);
            printf("%lld
    ",dp[1]);
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    关于java中final变量的小问题
    你在努力工作吗?
    Google Android系统中侵犯Oracle的专利说明
    应用系统之间数据传输的几种方式
    Java内存模型jsr133规范介绍
    程序员40岁之后怎么办?
    eaby技术架构变迁
    缓存使用的一些注意事项
    java对象初始化顺序
    Ubuntu安装Fcitx(小企鹅五笔输入法)
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13449001.html
Copyright © 2011-2022 走看看