kuangbin专题四:最短路练习

POJ2387 Til the Cows Come Home

思路:dijkstra搜索。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

const int maxn = 1005;
const int maxt = 2005;
int T, N;
int head[maxn], idx;
bool vis[maxn];
int dis[maxn];

struct Node{
    int u, dis;
    bool operator<(const Node& node) const{
        return dis > node.dis;
    }
};

struct Edge{
    int v, w, next;
} edge[2 * maxt];

void addEdge(int u, int v, int w){
    idx++;
    edge[idx].v = v, edge[idx].w = w;
    edge[idx].next = head[u];
    head[u] = idx;
}

void dijkstra(){
    priority_queue<Node> q;
    memset(dis, 0x3f, sizeof(dis));
    dis[N] = 0;

    Node firstNode = {N, 0};
    q.push(firstNode);
    while(q.size()){
        Node node = q.top(); q.pop();
        int u = node.u;
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = head[u]; i; i = edge[i].next){
            int v = edge[i].v, w = edge[i].w;
            if(!vis[v] && dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                Node nextNode = {v, dis[v]};
                q.push(nextNode);
            }
        }
    }
}

int main(){
    cin >> T >> N;
    for(int i = 1; i <= T; i++){
        int u, v, w;
        cin >> u >> v >> w;
        addEdge(u, v, w);
        addEdge(v, u, w);
    }
    dijkstra();
    cout << dis[1] << endl;
    return 0;
}
View Code

 

POJ2253 Frogger

思路:dijkstra搜索。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;

const int maxn = 205;
int N;
int head[maxn], idx;
bool vis[maxn];
double dis[maxn];

struct Pos{
    int x, y;
}pos[maxn];

struct Node{
    int u;
    double dis;
    bool operator<(const Node& node) const{
        return dis > node.dis + 1e-6;
    }
};

struct Edge{
    int v, next;
    double w;
} edge[2 * maxn * maxn];

void addEdge(int u, int v, double w){
    idx++;
    edge[idx].v = v, edge[idx].w = w;
    edge[idx].next = head[u];
    head[u] = idx;
}

double Distance(Pos& a, Pos& b){
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

void dijkstra(){
    priority_queue<Node> q;
    for(int i = 0; i <= N; i++) dis[i] = 0x3f3f3f3f;
    dis[1] = 0;

    Node firstNode = {1, 0};
    q.push(firstNode);
    while(q.size()){
        Node node = q.top(); q.pop();
        int u = node.u;
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = head[u]; i; i = edge[i].next){
            int v = edge[i].v;
            double w = edge[i].w;
            if(!vis[v] && dis[v] > max(w, dis[u]) + 1e-6){
                dis[v] = max(w, dis[u]);
                Node nextNode = {v, dis[v]};
                q.push(nextNode);
            }
        }
    }
}

void init(){
    memset(vis, 0, sizeof(vis));
    memset(head, 0, sizeof(head));
    idx = 0;
}

int main(){
    int testId = 0;
    while(cin >> N && N){
        testId++;
        init();
        for(int i = 1; i <= N; i++) cin >> pos[i].x >> pos[i].y;

        for(int i = 1; i < N; i++)
            for(int j = i + 1; j <= N; j++){
                double d = Distance(pos[i], pos[j]);
                addEdge(i, j, d);
                addEdge(j, i, d);
            }
        dijkstra();
        printf("Scenario #%d\n", testId);
        printf("Frog Distance = %.3f\n", dis[2]);
        printf("\n");
    }
    return 0;
}
View Code

 

POJ1797 Heavy Transportation

思路:用dijkstra好像会超时,用最小生成树和spfa都可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;

const int maxn = 1005;
const int maxm = 1000005;
int n, m, idx;
int head[maxn], dis[maxn];
bool in_queue[maxn];

struct Edge{
    int v, next;
    int w;
} edge[2 * maxm];

void addEdge(int u, int v, int w){
    idx++;
    edge[idx].v = v, edge[idx].w = w;
    edge[idx].next = head[u];
    head[u] = idx;
}

void spfa(){
    memset(in_queue, 0, sizeof(in_queue));
    memset(dis, 0, sizeof(dis));
    queue<int> q;
    q.push(1);
    in_queue[1] = true, dis[1] = 0x3f3f3f3f;
    while(q.size()){
        int u = q.front(); q.pop();
        in_queue[u] = false;
        for(int i = head[u]; i; i = edge[i].next){
            int v = edge[i].v, w = edge[i].w;
            if(dis[v] < min(dis[u], w)){
                dis[v] = min(dis[u], w);
                if(!in_queue[v]){
                    in_queue[v] = true;
                    q.push(v);
                }
            }
        }
    }
}

void init(){
    memset(head, 0, sizeof(head));
    memset(edge, 0, sizeof(edge));
    idx = 0;
}

int main(){
    int T;
    scanf("%d", &T);
    for(int t = 1; t <= T; t++){
        init();
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i++){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            addEdge(u, v, w);
            addEdge(v, u, w);
        }
        spfa();
        printf("Scenario #%d:\n", t);
        printf("%d\n\n", dis[n]);
    }
    return 0;
}
View Code

 

POJ3268 Silver Cow Party

思路:反向建图,两次dijkstra。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 1005;
const int maxm = 1e5 + 5;
int dis[maxn], rdis[maxn], head[maxn], rhead[maxn];
bool vis[maxn];
int idx;

struct Node{
    int u, dis;
    bool operator<(const Node& node) const{
        return dis > node.dis;
    }
};

struct Edge{
    int v, w, next;
} edge[maxm], redge[maxm];

void dijkstra(Edge* e, int* d, int* h, int x){
    memset(vis, 0, sizeof(vis));
    priority_queue<Node> q;
    Node node = {x, 0};
    q.push(node);
    d[x] = 0;

    while(q.size()){
        Node unode = q.top(); q.pop();
        int u = unode.u;
        vis[u] = true;
        for(int i = h[u]; i; i = e[i].next){
            int v = e[i].v, w = e[i].w;
            if(!vis[v] && d[v] > d[u] + w){
                d[v] = d[u] + w;
                Node node = {v, d[v]};
                q.push(node);
            }
        }
    }
}

int main(){
    int n, m, x;
    cin >> n >> m >> x;
    memset(dis, 0x3f, sizeof(dis));
    memset(rdis, 0x3f, sizeof(rdis));

    for(int i = 1; i <= m; i++){
        int u, v, w;
        cin >> u >> v >> w;
        idx++;
        edge[idx] = {v, w, head[u]};
        head[u] = idx;
        redge[idx] = {u, w, rhead[v]};
        rhead[v] = idx;
    }
    dijkstra(edge, dis, head, x);
    dijkstra(redge, rdis, rhead, x);

    int ans = 0;
    for(int i = 1; i <= n; i++){
        ans = max(ans, dis[i] + rdis[i]);
    }
    cout << ans << endl;

    return 0;
}
View Code

 

POJ1860 Currency Exchange

 思路:BellmanFord。

 

POJ3259 Wormholes

思路:BellmanFord、Flody算法都可。

 

POJ1502 MPI Maelstrom

思路:水题。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 110;
int n;
int head[maxn], idx;
int dis[maxn];
bool vis[maxn];

struct Node{
    int u;
    bool operator<(const Node &a) const {
        return dis[u] > dis[a.u];
    }
};

struct Edge{
    int v, w, next;
}edge[maxn * maxn];

void addedge(int u, int v, int w){
    idx++;
    edge[idx] = {v, w, head[u]};
    head[u] = idx;
}

int dijkstra(){
    memset(dis, 0x3f, sizeof(dis));
    priority_queue<Node> q;
    dis[1] = 0;
    Node n1 = {1};
    q.push(n1);

    while (q.size()) {
        Node p = q.top(); q.pop();
        if (vis[p.u]) continue;
        vis[p.u] = true;
        for (int i = head[p.u]; i; i = edge[i].next) {
            Edge &e = edge[i];
            if (!vis[e.v] && dis[e.v] > dis[p.u] + e.w) {
                dis[e.v] = dis[p.u] + e.w;
                Node ni = {e.v};
                q.push(ni);
            }
        }
    }
    int result = 0;
    for (int i = 1; i <= n; i++)
        result = max(result, dis[i]);
    return result;
}

int ch2i(char *wc){
    if (wc[0] == 'x')
        return 0x3f3f3f3f;
    int result = 0;
    for(int i = 0; wc[i]; i++) {
        result *= 10;
        result += wc[i] - '0';
    }
    return result;
}

void readMatrix() {
    char wc[10];
    for (int i = 2; i <= n; i++)
        for (int j = 1; j < i; j++) {
            cin >> wc;
            int wi = ch2i(wc);
            addedge(i, j, wi);
            addedge(j, i, wi);
        }
}

int main() {
    cin >> n;
    readMatrix();
    cout << dijkstra();
}
View Code

 

POJ3660 Cow Contest

思路:简单flody算法。

#include<iostream>
using namespace std;
const int maxn = 110;
int n, m, u, v;
int dis[maxn][maxn];

void flody(){
    for(int k = 1; k <= n; k++)
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                if(dis[i][k] &&  dis[k][j])
                    dis[i][j] = 1;
}

int main() {
    cin >> n >> m;

    for(int i = 1; i <= m; i++){
        cin >> u >> v;
        dis[u][v] = 1;
    }

    flody();

    int res = 0;
    for(int i = 1; i <= n; i++){
        int degree = 0;
        for(int j = 1; j <= n; j++)
            degree += dis[i][j] + dis[j][i];
        if(degree == n-1) res++;
    }
    cout << res << endl;
    return 0;
}
View Code

 

POJ2240 Arbitrage

思路:Bellman-ford判断是否有环。

#include<iostream>
#include<cstring>
#include<map>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 35;
int n, m, T, idx;
float dis[maxn];

struct Edge{
    int u, v;
    float rate;
}e[maxn * maxn];

void addedge(int u, int v, float rate){
    idx++;
    e[idx].u = u, e[idx].v = v;
    e[idx].rate = rate;
}

int main() {
    while(cin >> n && n){
        T++;
        memset(dis, 0, sizeof(dis));
        dis[1] = 1;

        // get all currency name
        map<string, int> mp;
        for(int i = 1; i <= n; i++){
            string currency;
            cin >> currency;
            mp[currency] = i;
        }

        cin >> m;

        // read exchange data
        string currency1, currency2;
        float rate;
        idx = 0;
        for(int i = 1; i <= m; i++){
            cin >> currency1 >> rate >> currency2;
            int c1 = mp[currency1], c2 = mp[currency2];
            addedge(c1, c2, rate);
        }

        // bellman-ford
        for(int k = 1; k <= n; k++){
            for(int i = 1; i <= m; i++){
                int u = e[i].u, v = e[i].v;
                float w = e[i].rate;
                if(dis[u] * w > dis[v])
                    dis[v] = dis[u] * w;
            }
        }

        // check if result is legal
        bool res = true;
        for(int i = 1; i <= m; i++){
            int u = e[i].u, v = e[i].v;
            float w = e[i].rate;
            if(dis[u] * w - 1e-7 > dis[v]){
                res = false;
                break;
            }
        }
        cout << "Case " << T << ": " << (res ? "No" : "Yes") << endl;
    }
    return 0;
}
View Code

 

POJ1511 Invitation Cards

思路:反向建图。花费要用long long类型,否则会WA。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 5;
int T, P, Q;
long long dis[maxn], rdis[maxn];
int head[maxn], rhead[maxn];
bool vis[maxn], rvis[maxn];

struct Edge{
    int v, w, next;
} e[maxn], re[maxn];

int idx, ridx;
void addedge(int u, int v, int w, Edge *e, int *head, int &idx){
    idx++;
    e[idx].v = v, e[idx].w = w;
    e[idx].next = head[u];
    head[u] = idx;
}

void spfa(Edge* e, int* head, long long* dis, int idx, bool *vis){
    queue<int> q;
    q.push(1);
    vis[1] = true;

    while(q.size()){
        int u = q.front(); q.pop();
        vis[u] = false;
        for(int i = head[u]; i; i = e[i].next){
            int v = e[i].v, w = e[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                if(!vis[v]){
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
}

void init(){
    idx = 0;
    memset(dis, 0x3f, sizeof(dis));
    memset(head, 0, sizeof(head));
    memset(rdis, 0x3f, sizeof(rdis));
    memset(rhead, 0, sizeof(rhead));
    dis[1] = rdis[1] = 0;
}

inline int read(){
    int s = 0, w = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-') w = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
    return s * w;
}

int main() {
    T = read();
    while(T--){
        init();
        P = read(), Q = read();
        for(int i = 1; i <= Q; i++){
            int u, v, w;
            u = read(), v = read(), w = read();
            addedge(u, v, w, e, head, idx);
            addedge(v, u, w, re, rhead, ridx);
        }
        spfa(e, head, dis, idx, vis);
        spfa(re, rhead, rdis, ridx, rvis);

        long long res = 0;
        for(int i = 1; i <= P; i++)
            res += dis[i] + rdis[i];
        cout << res << endl;
    }
    return 0;
}
View Code

 

POJ3159 Candies

 思路:差分约束。忘记调dijkstra函数了,debug好长时间和(;´д`)ゞ,最后还是借鉴了他人的代码发现了问题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int maxn = 3e4 + 5;
const int maxm = 15e4 + 5;
int N, M;
int head[maxn], dis[maxn];
int idx;

struct Edge{
    int v, w, next;
} e[maxm];

void addedge(int u, int v, int w){
    e[++idx] = {v, w, head[u]};
    head[u] = idx;
}

void dijkstra(){
    memset(dis, 0x3f, sizeof(dis));
    dis[1] = 0;

    priority_queue<P, vector<P>, greater<P> > q;
    q.push(P(0, 1));

    while(q.size()){
        P np = q.top(); q.pop();
        int u = np.second;
        if(dis[u] < np.first) continue;

        for(int i = head[u]; i; i = e[i].next){
            int v = e[i].v, w = e[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                q.push(P(dis[v], v));
            }
        }
    }
}

int read(){
    int x = 0, s = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-') s = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x << 1) + (x << 3) + (ch ^48);
        ch = getchar();
    }
    return x * s;
}

int main() {
    N = read(), M = read();
    for(int i = 1; i <= M; i++){
        int u, v, w;
        u = read(), v = read(), w = read();
        addedge(u, v, w);
    }
    dijkstra();
    cout << dis[N] << endl;
    return 0;
}
View Code

 

POJ2502 Subway

思路:最短路,建图麻烦,题目中距离的描述不清晰,取整方式也没说。暂时不想写。

 

POJ1062 昂贵的聘礼

思路:题目好蠢,下一题。

 

POJ1847 Tram

思路:每个点最多需要通过一次即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int maxn = 105;
int N, A, B;
int head[maxn], dis[maxn];
bool vis[maxn];
int idx;

struct Edge{
    int v, w, next;
} e[maxn * maxn];

void addedge(int u, int v, int w){
    e[++idx] = {v, w, head[u]};
    head[u] = idx;
}

void spfa(int A){
    memset(dis, 0x3f, sizeof(dis));
    dis[A] = 0;
    queue<int> q;
    q.push(A);
    vis[A] = true;

    while(q.size()){
        int u = q.front(); q.pop();
        vis[u] = false;
        for(int i = head[u]; i; i = e[i].next){
            int v = e[i].v, w = e[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                if(!vis[v]){
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
}

int main() {
    scanf("%d%d%d", &N, &A, &B);
    for(int u = 1; u <= N; u++){
        int k, v;
        scanf("%d%d", &k, &v);
        addedge(u, v, 0);
        for(int j = 1; j < k; j++){
            scanf("%d", &v);
            addedge(u, v, 1);
        }
    }
    spfa(A);
    cout << (dis[B] == 0x3f3f3f3f ? -1 : dis[B]) << endl;
    return 0;
}
View Code

 

LightOJ1074 Extended Traffic

思路:题目描述真是一言难尽,下一题。

 

HDU4725 The Shortest Path in Nya Graph

思路:结点分多层,如果直接把相邻层结点连接,会超内存限制。一个简单的解决方案是增加一个中间结点代表某一层,然后建图。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 5;
// head[n + i] represents the node of i-th layer to i+1-th layer
int head[maxn * 2], dis[maxn * 2];
bool vis[maxn * 2];
int idx;

struct Edge{
    int v, w, next;
} e[maxn * 5];

void addedge(int u, int v, int w){
    e[++idx] = {v, w, head[u]};
    head[u] = idx;
}

void spfa(){
    memset(dis, 0x3f, sizeof(dis));
    dis[1] = 0;

    queue<int> q;
    q.push(1); vis[1] = true;

    while(q.size()){
        int u = q.front(); q.pop();
        vis[u] = false;
        for(int i = head[u]; i; i = e[i].next){
            int v = e[i].v, w = e[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                if(!vis[v]){
                    q.push(v);
                    vis[v] = true;
                }
            }
        }
    }
}

void init(){
    idx = 0;
    memset(head, 0, sizeof(head));
}

int main() {
    int T;
    int n, m, c;
    scanf("%d", &T);
    for(int t = 1; t <= T; t++){
        init();
        scanf("%d%d%d", &n, &m, &c);

        // add layer edge
        for(int i = 1; i <= n; i++){
            int layer;
            scanf("%d", &layer);
            addedge(n + layer, i, 0);
            if(layer > 1) addedge(i, n + layer - 1, c);
            if(layer < n) addedge(i, n + layer + 1, c);
        }

        // add extra edge
        for(int i = 1; i <= m; i++){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            addedge(u, v, w);
            addedge(v, u, w);
        }
        spfa();
        cout << "Case #" << t << ": " << (dis[n] == 0x3f3f3f3f ? -1 : dis[n]) << endl;
    }
    return 0;
}
View Code

 

HDU3416 Marriage Match IV

思路:多跑几次最短路。

 

HDU4370 0 or 1

思路:以前就做过的一道题,但是代码好像不是我的。把矩阵看作是联通图即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
#define P pair<int, int>
const int maxn = 303;
int n;
int C[maxn][maxn];
int vis[maxn], dis[maxn];

void spfa(int ss){
    queue<int> s;
    for(int i = 1; i <= n; i++){
        if(i==ss){
            dis[i] = 0x3f3f3f3f;
            vis[i] = 0;
        }
        else{
            dis[i] = C[ss][i];
            vis[i] = 1;
            s.push(i);
        }
    }
    while(!s.empty()){
        int u = s.front(); s.pop();
        vis[u] = 0;
        for(int v = 1; v <= n; v++){
            if(dis[v]>dis[u]+C[u][v]){
                dis[v] = dis[u] + C[u][v];
                if(vis[v]==0){
                    vis[v] = 1;
                    s.push(v);
                }
            }
        }
    }
}


int main(){
    while(~scanf("%d", &n)){
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                scanf("%d", &C[i][j]);
        spfa(1);
        int dis1 = dis[1], dis2 = dis[n];
        spfa(n);
        int dis3 = dis[n];
        int output = min(dis2, dis1+dis3);
        printf("%d\n", output);
    }
    return 0;
}
View Code

 

POJ3169 Layout

 思路:差分约束。专题最后一题,代码不想写了,就到此结束吧。

posted @ 2021-01-29 11:12  Nanachi  阅读(29)  评论(0)    收藏  举报