1. 程式人生 > >HNUM1370: 巍巍嶽麓解題報告---(所有生成樹情況中最大邊權值的最小值)

HNUM1370: 巍巍嶽麓解題報告---(所有生成樹情況中最大邊權值的最小值)

題目描述

嶽麓山風景區位於湖南省長沙市嶽麓區,佔地面積 35.20 平方公里,是南嶽衡山 72 峰的最後一峰,位於
橘子洲旅遊景區內,為城市山嶽型風景名勝區,是中國四大賞楓勝地之一。
嶽麓山位於首批國家歷史文化名城長沙市湘江西岸,依江面市,現有嶽麓山、橘子洲、嶽麓書院、新民學
會四個核心景區,為世界罕見的集“山、水、洲、城”於一體的國家 AAAAA 級旅遊景區、國家重點風
景名勝區、湖湘文化傳播基地和愛國主義教育的示範基地。
嶽麓山因南朝宋時《南嶽記》中“南嶽周圍八百里,回燕為首,嶽麓為足”而得名,融中國古文化精華的
儒、佛、道為一體,包容了歷史上思想鉅子、高僧名道、騷人墨客共同開拓的嶽麓山文化內涵。景區內有
嶽麓書院、愛晚亭、麓山寺、雲麓宮、新民學會舊址、黃興墓、蔡鍔墓、第九戰區司令部戰時指揮部舊址
等景點。
為了改善嶽麓山周邊的旅遊環境,市長決定對道路進行改造,城市中有 n 個路口,有些交叉路口之間有
道路直接相連;兩個交叉路口之間最多有一條道路相連線。這些道路是雙向的,且能把所有的交叉路口直
接或間接連線起來。每條道路都有一個分值,分值越小表示這個道路越繁忙,越需要改造。但是市政府的
資金有限,市長希望進行改造的道路越少越好,於是提出了下面的要求,需要同時滿足:
1、改造的那些道路能把所有的交叉路口直接或間接地連通起來;
2、改造的道路儘量少且改造的那些道路中分值最大的道路的分值儘量小;
3、緊鄰嶽麓山的麓山南路必須改造。
請你做出規劃設計,選擇哪些道路應當改造。

輸入

單組資料。
輸入第一行有兩個正整數 n 和 m,分別表示城市有 n 個交叉路口,m 條道路 (n <= 3000,m<=4000)。
接下來 m 行是對每條道路的描述,u,v,c 表示交叉路口 u 和 v 之間有道路相連,分值為 c(分值不會超
過 int)。最後一行兩個正整數 s 和 t,表示麓山南路在交叉路口 s 和 t 相連的路上。

輸出

輸出兩個整數 tot,max,表示你選出了幾條道路,分值最大的那條的道路的分值是多少。

樣例輸入

4 5
1 2 3
1 4 5
2 4 7
2 3 6
3 4 8
1 4

樣例輸出

3 6

題意:麓山南路必須連通,所有連通圖情況中,最小的最大邊權值。

所以這個題不是最小生成樹!

思路:所有連通生成樹中最大邊權值的最小值。把所有邊權值排序後,找到必須連通的麓山南路下標index,最多有index種情況,取所有情況中最大邊權值的最小值。

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#define y1 AC
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define E 1e-12
const double pi = acos(-1);
const int MAX_N = 3005;
using namespace std;
int n, m;
int pre[MAX_N];
struct Node{
    int u, v, d;
};
Node G[4005];
bool cmp(Node a, Node b){
    return a.d < b.d;
}
void init(){
    for(int i = 1; i <= n; i++){
        pre[i] = i;
    }
}
int Find(int x){
    int i = x;
    while(x != pre[x]){
        x = pre[x];
    }
    int r = x;
    int j;
    while(i != r){
        j = pre[i];
        pre[i] = r;
        i = j;
    }
    return r;
}
int main()
{
    scanf("%d%d", &n, &m);
    //init();
    for(int i = 0; i < m; i++){
        int u, v, d;
        scanf("%d%d%d", &u, &v, &d);
        G[i].u = u, G[i].v = v, G[i].d = d;
    }
    sort(G, G + m, cmp);
    int x, y, index, maxs;
    scanf("%d%d", &x, &y);
    //pre[y] = x;
    for(int i = 0; i < m; i++){
        if((G[i].u == x && G[i].v == y) || (G[i].u == y && G[i].v == x)){
            index = i;
            break;
        }

    }
    int ans = INF;
    for(int i = 0; i <= index ; i++){
        init(); //並查集初始化
        pre[y] = x; //麓山南路必須連通
        maxs = G[index].d;  //麓上南路的邊權值
        int sum = 1;
        for(int j = i; j < m; j++){
            int fx = Find(G[j].u), fy = Find(G[j].v);
            if(fx != fy){
                pre[fy] = fx;
                sum++;
                maxs = max(maxs, G[j].d);
                if(sum == n - 1)    break;
            }
        }
        if(sum == n - 1){   //能夠形成連通生成樹
            ans = min(ans, maxs);
        }
    }
    printf("%d %d", n - 1, ans);
    return 0;
}