程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> HDU

HDU

編輯:關於C++

題目大意:有N個點,M條路,現在給出K條路,這K條路是在M條路中將權值擴大的路。每給出一條,就要求求出最小生成樹的權值
現在問每條路的最小生成樹的權值和/K的最小值是多少

解題思路:先得到最小生成樹,然後判斷路是不是最小生成樹的樹邊,如果不是,就不影響了
如果是的話,就要判斷一下是不是要去掉該邊,再添加新的邊。
如果去掉該邊的話,就相當於把最小生成樹劃分成了兩個塊,所以現在需要的是一條最小邊來連接兩個塊
我們設dp[u][v]為u到 v和到以v為根的樹的所有點的最小權值(以v為根就相當於有一條樹邊的一個結點是v的邊斷了,然後分成了兩個塊,而u和v在不同的塊),這個可以通過dfs得到
得到這個了,那就可以得到每條樹邊斷後,需要添加的最小權值邊了,也是通過dfs得到

#include 
#include 
#include 
using namespace std;

#define N 3010
#define ll long long
const int INF = 1000000000;

int n, m, tot;
int dis[N][N], best[N][N], d[N], f[N], dp[N][N];
bool vis[N];
vector G[N];

void init() {
    memset(dis, 0x3f, sizeof(dis));
    int u, v, c;
    for (int i = 0; i < m; i++) {
        scanf(%d%d%d, &u, &v, &c);
        dis[u][v] = dis[v][u] = c;
    }
}


ll prim() {
    memset(vis, 0, sizeof(vis));
    ll ans = 0;
    for (int i = 0; i < n; i++) {
        d[i] = dis[0][i];
        f[i] = 0;
        G[i].clear();
    }
    d[0] = INF;
    f[0] = -1;
    vis[0] = true;

    for (int i = 0; i < n - 1; i++) {
        int x = 0;
        for (int j = 1; j < n; j++)
            if (!vis[j] && d[j] < d[x])
                x = j;

        vis[x] = true;
        ans += d[x];

        if (f[x] != -1) {
            G[x].push_back(f[x]);
            G[f[x]].push_back(x);
        }

        for (int j = 1; j < n; j++) 
            if (!vis[j] && d[j] > dis[x][j]) {
                d[j] = dis[x][j]; 
                f[j] = x;
            }
    }
    return ans;
}

//得到dp[u][v]
int dfs1(int u, int fa, int root) {
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (v != fa) 
            dp[root][u] = min(dp[root][u], dfs1(v, u, root));
    }
    if (fa != root) dp[root][u] = min(dp[root][u], dis[root][u]);
    return dp[root][u];
}

//得到樹邊斷裂後需要的最小權值邊
int dfs2(int u, int fa, int root) {
    int ans = dp[u][root];
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (v != fa) ans = min(ans, dfs2(v, u, root));
    }
    return ans;
}

void solve() {
    memset(dp, 0x3f, sizeof(dp));
    ll MinTreeValue = prim();
    double ans = 0;
    for (int i = 0; i < n; i++)
        dfs1(i, -1, i);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < G[i].size(); j++) {
            int v = G[i][j];
            best[i][v] = best[v][i] = dfs2(v, i, i); 
        }
    int u, v, c, q;
    scanf(%d, &q);
    for (int i = 0; i < q; i++) {
        scanf(%d%d%d, &u, &v, &c);
        if (f[u] != v && f[v] != u) 
            ans += MinTreeValue * 1.0;
        else
            ans += MinTreeValue * 1.0 - dis[u][v] + min(best[u][v], c);
    }

    printf(%.4f
, ans / q);
}

int main() {
    while (scanf(%d%d, &n, &m) != EOF && n + m ) {
        init();
        solve();
    }
    return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved