信息學一本通 祕密的牛奶運輸 求次小生成樹

題目描述
農夫約翰要把他的牛奶運輸到各個銷售點。

運輸過程中,可以先把牛奶運輸到一些銷售點,再由這些銷售點分別運輸到其他銷售點。

運輸的總距離越小,運輸的成本也就越低。

低成本的運輸是農夫約翰所希望的。

不過,他並不想讓他的競爭對手知道他具體的運輸方案,所以他希望採用費用第二小的運輸方案而不是最小的。

現在請你幫忙找到該運輸方案。

注意:

如果兩個方案至少有一條邊不同,則我們認爲是不同方案;
費用第二小的方案在數值上一定要嚴格小於費用最小的方案;
答案保證一定有解;
輸入格式
第一行是兩個整數 N,M,表示銷售點數和交通線路數;

接下來 M 行每行 3 個整數 x,y,z,表示銷售點 x 和銷售點 y 之間存在線路,長度爲 z。

輸出格式
輸出費用第二小的運輸方案的運輸總距離。

數據範圍
1≤N≤500,
1≤M≤104,
1≤z≤109,
數據中可能包含重邊。

輸入樣例:
4 4
1 2 100
2 4 200
2 3 250
3 4 100
輸出樣例:
450

思路

  1. 我們先求出最小生成樹
  2. 把樹建成圖, 然後進行樹的遍歷, 存下a->b這條邊的最大邊權和嚴格次大邊權
  3. 最後我們遍歷每一條題目中給出的邊, 如果這條邊沒有在樹中, 同時它又比這條邊上的最大權值大, 就替換掉最大權值,如果比次大權值大, 就替換掉次大權值
    在這裏插入圖片描述

代碼

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const  int N = 510, M = 10010;

int f[N];
struct node{
    int x, y, dis;
    bool is_tree;
    bool operator<(const node &a) const 
    {
        return dis < a.dis;
    }
}ed[M];
int n, m;
int dis[N][N], dis2[N][N];
int e[M], w[M], ne[M], h[N], len;

void add(int a, int b, int c)
{
    e[len] = b;
    w[len] = c;
    ne[len] = h[a];
    h[a] = len++;
}

void init()
{
    for(int i = 0; i < N; i++)
        f[i] = i;
}

int find(int x)
{
    if(f[x] == x)return x;
    return f[x] = find(f[x]);
}

void dfs(int u, int fa, int maxd1, int maxd2, int dis1[], int dis2[])
{
    dis1[u] = maxd1;
    dis2[u] = maxd2;
    for(int i = h[u]; ~i; i = ne[i])
    {
        int y = e[i];
        if(y != fa)
        {
          //  cout << u << " " << y << endl;
            int td1 = maxd1, td2 = maxd2;
            int c = w[i];
            if(c > maxd1)
                td2 = td1, td1 = c;
            else if(c < maxd1 && c > maxd2)
                td2 = c;
            dfs(y, u, td1, td2, dis1, dis2);
        }
    }
}

int main()
{

    cin >> n >> m;
    init();
    for(int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        ed[i] = {a, b, c};
    }
    
    long long sum = 0;
    memset(h, -1, sizeof h);
    sort(ed + 1, ed + m + 1);
    for(int i = 1; i <= m; i++)
    {
        int x = find(ed[i].x);
        int y = find(ed[i].y);
        if(x != y)
          {
              int a = ed[i].x;
              int b = ed[i].y;
            int z = ed[i].dis;
            f[x] = y;
            add(a, b, z);
            add(b, a, z);
            ed[i].is_tree = true;
            sum += ed[i].dis;
        }
        else ed[i].is_tree = false;
    }

    for(int i = 1; i <= n; i++) dfs(i, -1, -1e9, -1e9,  dis[i], dis2[i]);

    long long ans = 1e18;
    for(int i =1; i <= m; i++)
    {
         if(!ed[i].is_tree)
            {
                int z = ed[i].dis;
                int a = ed[i].x;
                int b = ed[i].y;
                if(z > dis[a][b])
                     ans = min(ans, sum - dis[a][b] + z);
                else if(z > dis2[a][b])
                    ans = min(ans, sum - dis2[a][b] + z);
            }
    }
           
        
    cout << ans << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章