loj136 (最小瓶頸路,屢次詢問)

 

題目描述

給定一個包含 n nn 個節點和 m mm 條邊的圖,每條邊有一個權值。
你的任務是回答 k kk 個詢問,每一個詢問包含兩個正整數 s ss 和 t tt 表示起點和終點,要求尋找從 s ss 到 t tt 的一條路徑,使得路徑上權值最大的一條邊權值最小。
html

輸入格式

第一行包含三個整數 n nn、m mm、k kk,分別表示 n nn 個節點, m mm 條路徑, k kk 個詢問。c++

接下來 m mm 行,每行三個整數 u uu , v vv , w ww, 表示一個由 u uu 到 v vv 的長度爲 w ww 的雙向邊。數組

再接下來 k kk 行,每行兩個整數 s ss , t tt,表示詢問從 s ss 鏈接到 t tt 的全部路徑中單邊長度最大值的最小值。app

輸出格式

輸出包含 k kk 行,每一行包含一個整數 p pp 。p pp 表示 s ss 鏈接到 t tt 的全部路徑中單邊長度最大值的最小值。另外,若是 s ss 到 t tt 沒有路徑相連通,輸出 -1 便可。ui

樣例

樣例輸入

8 11 3
1 2 10
2 5 50
3 4 60
7 5 60
3 6 30
1 5 30
6 7 20
1 7 70
2 3 20
3 5 40
2 6 90
1 7
2 8
6 2

樣例輸出

30
-1
30

數據範圍與提示

對於 30% 30\%30% 的數據 n≤100,m≤1000,k≤100,w≤1000 n \leq 100, m \leq 1000, k \leq 100, w \leq 1000n100,m1000,k100,w100
對於 70% 70\%70% 的數據 n≤1000,m≤10000,k≤1000,w≤100000 n \leq 1000, m \leq 10000, k \leq 1000, w \leq 100000n1000,m10000,k1000,w10000
對於 100% 100\%100% 的數據 n≤1000,m≤100000,k≤1000,w≤10000000 n \leq 1000, m \leq 100000, k \leq 1000, w \leq 10000000n1000,m100000,k1000,w1000000
本題可能會有重邊。
爲了不 Special Judge,本題全部的 w ww 均不相同。
spa

題解:

一樣是基於最小生成樹,咱們將其中關鍵信息保存code

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1000+10;
const int INF=0x3f3f3f3f;
int n,m,k;
int mapp[MAXN][MAXN];
int ans[MAXN][MAXN],dis[MAXN],pri[MAXN];
bool vis[MAXN];
void prim()
{
    memset(vis, false, sizeof(vis));
    for (int i = 1; i <=n ; ++i)
    {
        dis[i]=INF;
        pri[i]=i;
    }
    dis[1]=0;
    for (int i = 1; i <=n ; ++i) {
        int MAXX=INF,v=-1;
        for (int j = 1; j <=n ; ++j) {
            if(!vis[j]&&dis[j]<MAXX)
            {
                MAXX=dis[v=j];
            }
        }
        if(v==-1)
            break;
        for (int j = 1; j <=n ; ++j) {
            if(vis[j])
            {
                ans[v][j]=ans[j][v]=max(ans[pri[v]][j],MAXX);
            }
        }
        vis[v]=true;
        for (int j = 1; j <=n ; ++j) {
            if(!vis[j]&&mapp[v][j]<dis[j])
            {
                dis[j]=mapp[v][j];
                pri[j]=v;
            }
        }
    }
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int x,y,z;
    memset(mapp,0x3f, sizeof(mapp));
    memset(ans,0, sizeof(ans));
    for (int i = 0; i <=n ; ++i) {
        mapp[i][i]=0;
    }
    for (int i = 0; i <m ; ++i) {
        scanf("%d%d%d",&x,&y,&z);
        if(mapp[x][y]>z)
            mapp[x][y]=mapp[y][x]=z;
    }
    prim();
    while(k--)
    {
        scanf("%d%d",&x,&y);

        printf("%d\n",ans[x][y]==0?-1:ans[x][y]);
    }
    return 0;
}


//int prim(int s)
//{
//    int res=0;
//    memset(ans,0,sizeof(ans));// 初始化目標數組
//    for(int i=1;i<=n;i++)
//        vis[i] = false, d[i] = INF, pri[i]=i;//初始化 標記、距離、父親數組。
//
//    d[s]=0; // 自身的距離爲零
//    for(int i=0;i<n;i++) // prim考察剩下的n - 1個點
//    {
//        int maxx=INF, v=-1; // 比較和點的位置
//        for(int j=1;j<=n;j++) // 尋找與最小生成樹集合最近的點
//        {
//            if(!vis[j]&&d[j]<maxx)
//            {
//                maxx=d[v=j]; // 寫法不錯
//            }
//        }
//        if(v==-1) // 未找到的判斷
//            break;
//
//        for(int j=1;j<=n;j++) //
//            if(vis[j])
//                ans[v][j] = ans[j][v] = max(ans[pri[v]][j], maxx);
//
//        res+=maxx; // 最小生成樹權值更新
//        vis[v]=true; // 將找到的點加入集合
//
//        for(int j=1;j<=n;j++)
//        {
//            if(!vis[j]&&mapp[v][j]<d[j])
//            {
//                d[j] = mapp[v][j]; // 更新距離
//                pri[j] = v; // 更新父親節點。
//            }
//        }
//    }
//    return res;
//}
相關文章
相關標籤/搜索