zoukankan      html  css  js  c++  java
  • HDU4126

    HDU4126 - 最小生成树 + DP

    题目链接

    题目大意

    给你一个图,有q次询问,每次询问如果替换一条边后最小生成树的大小是多少,求q次询问的平均值。(要替换的边的权一定不小于原来边权,替换只在当前次询问有效)

    数据范围

    多组输入T<=20,1N3000,0MNN,边权ci1071Q10000

    解题思路

    首先找到一颗最小生成树,之后当要替换的边不在最小生成树里的话,当前的最小生成树就直接是最小生成树的值。如果要替换的边在最小生成树里面的话,比如(u,v)边是要替换的边,将(u,v)删掉之后就会形成两个子树,就需要找出一条能连接这两个子树最小的那条边,那我们就可以实现处理出最小生成树上每条边的最小替换值。假如要替换的边一端是点p,那么假如p在u子树中,只需要在v子树中找到一个连接p的一条最小的边。那么做n次dfs,每次dfs处理以i点为根,且以i作为要替换的一个端点时(u,v)边的最小替换值,这样就n2处理出了最小生成树中所有边的最小替换值。而dfs时,假如从点i遍历到了u,u遍历v时,要找(u,v)的最小替换边,只需要找到i与v子树中所有边的最小值。但如果要找的是(i,u)边的最小替换边,那就不能包括点u了,因为u和i是直接相连的,是要被替换的,所以只能是i连u子树且除了u点之外的点的最小边。

    AC代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long LL;
    const int INF = 1e9 + 7;
    const int maxn = 3000;
    int n, m, q;
    vector<int>E[maxn + 5];
    LL sum;
    bool vis[maxn + 5];
    int dis[maxn + 5], dp[maxn + 5][maxn + 5], a[maxn + 5][maxn + 5];
    int pre[maxn + 5];
    void Prim(int x) {
        sum = 0LL;
        for(int i = 0; i < n; i++) dis[i] = a[x][i], pre[i] = x, vis[i] = 0, E[i].clear();
        vis[0] = 1, pre[0] = -1, dis[0] = INF;
        for(int i = 1; i < n; i++) {
            int k = 0;
            for(int j = 0; j < n; j++) {
                if(!vis[j] && dis[k] > dis[j])k = j;
            }
            vis[k] = 1;
            if(pre[k] != -1) {//建最小生成树
                E[k].push_back(pre[k]);
                E[pre[k]].push_back(k);
            }
            sum += (LL)dis[k];
            for(int j = 0; j < n; j++) {
                if(!vis[j] && dis[j] > a[k][j]) {
                    dis[j] = a[k][j];
                    pre[j] = k;
                }
            }
        }
    }
    int Dfs(int u, int fa, int p) {
        int res = INF;
        for(int i = 0; i < E[u].size(); i++) {
            int v = E[u][i];
            if(v != fa) {
                int tmp = Dfs(v, u, p);
                res = min(tmp, res);
                dp[u][v] = dp[v][u] = min(dp[u][v], tmp);
            }
        }
        if(p != fa)res = min(res, a[p][u]);
        return res;
    }
    int main() {
        while(~scanf("%d%d", &n, &m)) {
            if(n == 0 && m == 0)break;
            for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)a[i][j] = dp[i][j] = INF;
            for(int i = 1; i <= m; i++) {
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                a[u][v] = a[v][u] = w;
            }
            Prim(0);
            for(int i = 0; i < n; i++) Dfs(i, -1, i);//处理所有最小生成树上边的最小替换值
            scanf("%d", &q);
            LL res = 0LL;
            for(int i = 1; i <= q; i++) {
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                if(pre[u] != v && pre[v] != u) res += sum;
                else res += (sum - a[u][v] + min(w, dp[u][v]));
            }
            printf("%.4lf
    ", res * 1.0 / q);
        }
        return 0;
    }
  • 相关阅读:
    nginx使用vhost子目录
    nginx服务报错解决
    反向代理远端 单台tomcat 使用域名代理
    反向代理远端 单台tomcat 使用ip+端口
    nginx反向代理本地 两台web负载均衡 使用域名代理
    nginx反向代理本地 两台web负载均衡 使用ip+端口代理
    nginx反向代理本地 单台wed -使用域名代理
    nginx反向代理本地 单台wed -使用ip+端口代理
    php 在函数内引用全局变量 讲解引用
    Xdebug的安装与使用
  • 原文地址:https://www.cnblogs.com/TRDD/p/9813511.html
Copyright © 2011-2022 走看看