[kuangbin带你飞]专题四 最短路练习

时间:2023-02-13 19:59:39

A - Til the Cows Come Home

最短路模板,从终点到起点,双向建边

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/28 20:55:21
 * File Name   : 4_A.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define MAX_N 2000
int T, N;
struct node{
    int to;
    int cost;
    node(int _to, int _cost) : to(_to), cost(_cost){}
};
vector<node> G[MAX_N];
int d[MAX_N];
int dijsktra(){
    d[N] = 0;
    priority_queue<P , vector<P>, greater<P> >  que;
    que.push(P(d[N], N));
    while(que.size()){
        P q = que.top(); que.pop();
        int v = q.second;
        if(d[v] < q.first) continue;
        for(int i = 0;i < G[v].size(); i++){
            node &e = G[v][i];
            if(d[e.to] > d[v] + e.cost){
                d[e.to] = d[v] + e.cost;
                que.push(P(d[e.to], e.to));
            }
        }
    }
    return d[1];
}
int main() {
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> T >> N;
    memset(d, 0x3f, sizeof(d));
    for(int i = 0;i < T; i++){
        //构图
        int u, v, cost;
        cin >> u >> v >> cost;
        G[u].push_back(node(v, cost));
        G[v].push_back(node(u, cost));
    }
    int ans = dijsktra();
    cout << ans << endl;
    return 0;
}

B -Frogger

题目大意:

给出两只青蛙的坐标A、B,和其他的n-2个坐标,任一两个坐标点间都是双向连通的。显然从A到B存在至少一条的通路,每一条通路的元素都是这条通路中前后两个点的距离,这些距离中又有一个最大距离。

现在要求求出所有通路的最大距离,并把这些最大距离作比较,把最小的一个最大距离作为青蛙的最小跳远距离。

 

Floyd算法

用Floyd算法求出两两最短路,再求出从每个点开始的最长路,最后从这n个最长路中求出最小的那个即为所求。

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/29 10:55:02
 * File Name   : 4_B.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
typedef long long LL;
typedef pair<double, int> PII;
#define MAX_N 210 
int N;
double G[MAX_N][MAX_N];
struct Point{
    double x, y;
}P[MAX_N];

double solve(){
    for(int k = 0;k < N; k++){
        for(int i = 0;i < N-1; i++){
            for(int j = i+1; j < N; j++){
                if(G[i][k] < G[i][j] && G[k][j] < G[i][j]){
                    G[j][i] = G[i][j] = max(G[i][k], G[k][j]);
                }
            }
        }
    }
    return G[0][1];
}
int main() {
    //freopen("in.txt", "r", stdin);
    //cin.tie(0);
    //ios::sync_with_stdio(false);
    int cnt = 1;
    while(~scanf("%d", &N)){ 
        if(!N) break;
        printf("Scenario #%d\n", cnt++);
        for(int i = 0;i < N; i++){
            scanf("%lf%lf", &P[i].x, &P[i].y);
        }
        for(int i = 0;i < N-1; i++){
            for(int j = i+1; j < N; j++){
                double x = P[i].x - P[j].x;
                double y = P[i].y - P[j].y;
                double cost = sqrt(x*x + y*y);
                G[i][j] = G[j][i] = cost;
            }
        }
        double ans = solve();
        printf("Frog Distance = %.3f\n\n", ans);
    }
    return 0;
}

C - Heavy Transportation

和上个题要求的正好相反,求最短路径的一条边最小承载量,这里出发点要特殊处理,因为d[s] = 0;之后的点只要d[v] < d[u] && d[v] < cost就可用d[v] = min(d[u], cost)来推了,用的dijsktra,Floyd会超时

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/30 11:03:39
 * File Name   : 4_C.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
typedef long long LL;
typedef pair<int, int> P;
#define MAX_N 1010 
int N, M;
struct edge{
    int to;
    int cost;
    edge(int _to ,int _cost) :to(_to), cost(_cost){}
};

vector<edge> G[MAX_N];
int d[MAX_N];
int vis[MAX_N];
int solve(){
    memset(d, 0, sizeof(d));
    memset(vis, 0, sizeof(vis));
    d[1] = 0;
    priority_queue <int> que;
    for(int i = 0; i < G[1].size(); i++){
        //先处理起点,因为与后面不一样
        edge e = G[1][i];
        d[e.to] = e.cost;
        que.push(e.to);
    }
    //dijsktra
    while(que.size()){
        int v = que.top(); que.pop();
        for(int i = 0;i < G[v].size(); i++){
            edge e = G[v][i];
            if(d[e.to] < min(d[v], e.cost)){
                //同时小于边和上一个顶点时,才能更新
                d[e.to] = min(d[v], e.cost);
                que.push(e.to);
            }
        }
    }   
    return d[N];
}
int main() {
    //freopen("in.txt", "r", stdin);
    //cin.tie(0);
    //ios::sync_with_stdio(false);
    int cnt = 1;
    int t;
    scanf("%d", &t);
    while(t--){ 
        scanf("%d%d", &N, &M);
        printf("Scenario #%d:\n", cnt++);
        memset(G, 0, sizeof(G));
        for(int i = 0;i < M; i++){
            int a, b, cost;
            scanf("%d%d%d", &a, &b, &cost);
            G[a].push_back(edge(b, cost));
            G[b].push_back(edge(a, cost));
        }
        int ans = solve();
        printf("%d\n\n", ans);
    }
    return 0;
}
<span style="font-size:24px;color:#FF0000;">
</span>
D - Silver Cow Party

1.求i( 1<= i <=n)到X的最短路径,保存在d_1[i]

2.求X到所有i(1 <= i <= n)的最短路,保存在d_2[i]

3求一条最长的最短路 ans = max(ans, d_1[i] + d_2[i]) (1 <=  i <= n)

/***********************************************
 * Author: fisty
 * Created Time: 2015/1/30 17:51:30
 * File Name   : 4_D.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 1100
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
struct edge{
    int to;
    int cost;
    edge(int _to, int  _cost) : to(_to), cost(_cost){}
};
vector<edge> G[MAX_N];
int n, M ,X;
int d[MAX_N];
int d_1[MAX_N], d_2[MAX_N]; //去和回
int solve(){
    //memset(d_1, 0, sizeof(d_1));
    //memset(d_2, 0, sizeof(d_2));
    for(int i = 1;i <= n; i++){
        int s = i;           //出发点
        //从各个地方出发到X
        if(i == X) continue;
        priority_queue<P, vector<P>, greater<P> > que;
        memset(d, 0x3f, sizeof(d));
        d[s] = 0;
        que.push(P(d[s], s));
        while(que.size()){
            P q = que.top(); que.pop();
            int v = q.second;
            if(d[v] < q.first) continue;
            for(int j = 0;j < G[v].size(); j++){
                edge e = G[v][j];
                if(d[e.to] > d[v] + e.cost){
                    d[e.to] = d[v] + e.cost;
                    que.push(P(d[e.to], e.to));
                }
            }
        }
        d_1[i] = d[X];
        //Debug(d[X]);
    }
    //从X出发到各地
    priority_queue<P, vector<P>, greater<P> > que;
    memset(d, 0x3f, sizeof(d));
    d[X] = 0;
    que.push(P(d[X], X));
    while(que.size()){
        P q = que.top(); que.pop();
        int v = q.second;
        if(d[v] < q.first) continue;
        for(int i = 0;i < G[v].size(); i++){
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost){
                d[e.to] = d[v] + e.cost;
                que.push(P(d[e.to], e.to));
            }
        }
    }
    for(int i = 1; i <= n; i++){
        if(i == X) continue;
        d_2[i] = d[i];
        //Debug(d[i]);
    }
    //求一条最长的最短路
    int ans = -INF;
    for(int i = 1; i <= n; i++){
        if(i == X) continue;
        ans = max(ans, d_1[i] + d_2[i]);
    }
    return ans;
}
int main(){
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> n >> M >> X;
    for(int i = 0;i < M; i++){
        int a, b, cost;
        cin >> a >> b >> cost;
        //单向
        G[a].push_back(edge(b, cost));
    }
    int ans = solve();
    cout << ans << endl;
    return 0;
}


E - Currency Exchange

题目大意

有多种汇币,汇币之间可以交换,这需要手续费,当你用100A币交换B币时,A到B的汇率是29.75,手续费
是0.39,那么你可以得到(100 - 0.39) * 29.75 = 2963.3975 B币。问s币的金额经过交换最终得到的s币金额数能否增加
货币的交换是可以重复多次的,所以我们需要找出是否存在正权回路,且最后得到的s金额是增加的

怎么找正权回路呢?(正权回路:在这一回路上,顶点的权值能不断增加即能一直进行松弛)

题解链接