1. 程式人生 > >CCF習題 201703-4 地鐵修建(dijkstra 或者 最小生成樹)

CCF習題 201703-4 地鐵修建(dijkstra 或者 最小生成樹)

題意:

很水很水的一道題目, 但自己也很水, 沒得全分= = ~~~

求使得1和n 連通得一條路中最大路權最小值。

思路:

多個思路:

1. 修改dijkstra,把判斷距離改成判斷 最大路權即可。

2. 最小生成樹,直接按照最小生成樹做,當1和n 連通時就找到答案了,因為這時候肯定是邊最小的。

迪傑斯特拉版本程式碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define Siz(x) (int)x.size()
using namespace std;

const int maxn = 100000 + 10;
int n,m;

struct Edge{
    int f,t,w;

    Edge(int f=0,int t = 0,int w = 0):f(f),t(t),w(w){}
};


struct Node{
    int d,u;
    Node(int d = 0,int u = 0):d(d),u(u){}
    bool operator < (const Node& rhs) const {
        return d > rhs.d;
    }
};
vector<Edge>edges;

vector<int>g[maxn];
int sz = 0;
priority_queue<Node>q;
bool vis[maxn];
int dis[maxn];
int bfs(){
    q.push(Node(0,1));
    for (int i = 2; i <= n; ++i)dis[i] = 0x3f3f3f3f;
    dis[1] = 0;
    while(!q.empty()){
        Node o = q.top(); q.pop();
        int u = o.u;
        int d = o.d;
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = 0; i < Siz(g[u]); ++i){
            Edge& e = edges[g[u][i]];
            int nd = d;
            if (e.w > nd)nd = e.w;
            if (nd < dis[e.t]){
                dis[e.t] = nd;
                q.push(Node(nd,e.t));
            }
        }
    }
    return dis[n];
}

int main(){
    scanf("%d %d",&n, &m);
    for (int i = 0; i < m; ++i){
        int u,v,w;
        scanf("%d %d %d",&u, &v, &w);
        edges.push_back(Edge(u,v,w));
        sz++;
        g[u].push_back(sz-1);
        edges.push_back(Edge(v,u,w));
        sz++;
        g[v].push_back(sz-1);
    }
    printf("%d\n",bfs());
    return 0;
}
/**
6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6
**/



最小生成樹程式碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct Node{
    int u,v,w;
    bool operator < (const Node &rhs) const {
        return w < rhs.w;
    }
    void read(){
        scanf("%d %d %d",&u, &v, &w);
    }

}p[200000+10];
int fa[100000 + 10];
int find(int x){
    return fa[x] == x?x:fa[x] = find(fa[x]);

}

int main(){

    int n,m;
    scanf("%d %d",&n, &m);
    for (int i =1; i <= n; ++i)fa[i] = i;
    for (int i = 0; i < m; ++i){
        p[i].read();

    }
    sort(p,p+m);
    int ans = 0;
    int i;
    for (i = 0; i < m; ++i){
        if (find(n) == find(1))break;
        fa[find(p[i].u) ] = find(p[i].v);

    }
    printf("%d\n",p[i-1].w);
    return 0;
}
問題描述
試題編號: 201703-4
試題名稱: 地鐵修建
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述: 問題描述   A市有n個交通樞紐,其中1號和n號非常重要,為了加強運輸能力,A市決定在1號到n號樞紐間修建一條地鐵。
  地鐵由很多段隧道組成,每段隧道連線兩個交通樞紐。經過勘探,有m段隧道作為候選,兩個交通樞紐之間最多隻有一條候選的隧道,沒有隧道兩端連線著同一個交通樞紐。
  現在有n家隧道施工的公司,每段候選的隧道只能由一個公司施工,每家公司施工需要的天數一致。而每家公司最多隻能修建一條候選隧道。所有公司同時開始施工。
  作為專案負責人,你獲得了候選隧道的資訊,現在你可以按自己的想法選擇一部分隧道進行施工,請問修建整條地鐵最少需要多少天。 輸入格式   輸入的第一行包含兩個整數n, m,用一個空格分隔,分別表示交通樞紐的數量和候選隧道的數量。
  第2行到第m+1行,每行包含三個整數a, b, c,表示樞紐a和樞紐b之間可以修建一條隧道,需要的時間為c天。 輸出格式   輸出一個整數,修建整條地鐵線路最少需要的天數。 樣例輸入 6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6 樣例輸出 6 樣例說明   可以修建的線路有兩種。
  第一種經過的樞紐依次為1, 2, 3, 6,所需要的時間分別是4, 4, 7,則整條地鐵線需要7天修完;
  第二種經過的樞紐依次為1, 4, 5, 6,所需要的時間分別是2, 5, 6,則整條地鐵線需要6天修完。
  第二種方案所用的天數更少。 評測用例規模與約定   對於20%的評測用例,1 ≤ n ≤ 10,1 ≤ m ≤ 20;
  對於40%的評測用例,1 ≤ n ≤ 100,1 ≤ m ≤ 1000;
  對於60%的評測用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 10000,1 ≤ c ≤ 1000;
  對於80%的評測用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000;
  對於100%的評測用例,1 ≤ n ≤ 100000,1 ≤ m ≤ 200000,1 ≤ a, b ≤ n,1 ≤ c ≤ 1000000。

  所有評測用例保證在所有候選隧道都修通時1號樞紐可以通過隧道到達其他所有樞紐。