最短路 2016.4.17

1、HDU 2544 最短路

解题思路:
简单最短路

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 100 + 5;
int N, M;
int Map[maxn][maxn];
bool vis[maxn];
int dis[maxn];

void Dijkstra(void);

int main()
{
// freopen("in.txt", "r", stdin);
    while (cin>>N>>M && !(N==0&&M==0)) {
        memset(vis, false, sizeof(vis));
        int A, B, C;
        for (int i=1; i<=N; ++i) {
            for (int j=1; j<=N; ++j) {
                if (i == j) {
                    Map[i][j] = 0;
                } else {
                    Map[i][j] = INF;
                }
            }
        }
        dis[1] = 0;
        for (int i=2; i<=N; ++i) {
            dis[i] = INF;
        }
        for (int i=1; i<=M; ++i) {
            cin>>A>>B>>C;
            Map[A][B] = Map[B][A] = C;
        }
        Dijkstra();
        cout<<dis[N]<<endl;
    }
    return 0;
}

void Dijkstra(void)
{
    for (int i=2; i<=N; ++i) {
        dis[i] = Map[1][i];
    }
    vis[1] = true;
    for (int i=2; i<=N; ++i) {
        int Min = INF;
        int t;
        for (int j=2; j<=N; ++j) {
            if (!vis[j] && dis[j]<Min) {
                t = j;
                Min = dis[j];
            }
        }
        vis[t] = true;
        for (int j=2; j<=N; ++j) {
            if (!vis[j] && dis[t]+Map[t][j] < dis[j]) {
                dis[j] = dis[t] + Map[t][j];
            }
        }
    }
}
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 100 + 5;
int N, M;
int Map[maxn][maxn];

void Floyd(void);

int main()
{
// freopen("in.txt", "r", stdin);
    while (cin>>N>>M && !(N==0&&M==0)) {
        int A, B, C;
        for (int i=1; i<=N; ++i) {
            for (int j=1; j<=N; ++j) {
                if (i == j) {
                    Map[i][j] = 0;
                } else {
                    Map[i][j] = INF;
                }
            }
        }
        for (int i=1; i<=M; ++i) {
            cin>>A>>B>>C;
            Map[A][B] = Map[B][A] = C;
        }
        Floyd();
        cout<<Map[1][N]<<endl;
    }
    return 0;
}

void Floyd(void)
{
    for (int k=1; k<=N; ++k) {
        for (int i=1; i<=N; ++i) {
            for (int j=1; j<=N; ++j) {
                if (Map[i][k]+Map[k][j] < Map[i][j]) {
                    Map[i][j] = Map[i][k]+Map[k][j];
                }
            }
        }
    }
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 100 + 5;
int N, M;
int Map[maxn][maxn];
int dis[maxn];
bool vis[maxn];

void SPFA(void);

int main()
{
// freopen("in.txt", "r", stdin);
    while (cin>>N>>M && !(N==0&&M==0)) {
        int A, B, C;
        for (int i=1; i<=N; ++i) {
            for (int j=1; j<=N; ++j) {
                if (i == j) {
                    Map[i][j] = 0;
                } else {
                    Map[i][j] = INF;
                }
            }
        }
        for (int i=1; i<=M; ++i) {
            cin>>A>>B>>C;
            Map[A][B] = Map[B][A] = C;
        }
        SPFA();
        cout<<dis[N]<<endl;
    }
    return 0;
}

void SPFA(void)
{
    memset(vis, false, sizeof(vis));
    for (int i=1; i<=N; ++i) {
        dis[i] = INF;
    }
    dis[1] = 0;
    vis[1] = true;
    queue<int> Queue;
    Queue.push(1);
    while (!Queue.empty()) {
        int t = Queue.front();
        Queue.pop();
        vis[t] = false;
        for (int i=1; i<=N; ++i) {
            if (dis[i] > dis[t]+Map[t][i]) {
                dis[i] = dis[t] + Map[t][i];
                if (!vis[i]) {
                    Queue.push(i);
                    vis[i] = true;
                }
            }
        }
    }
}

2、POJ 1797 Heavy Transportation

题意:
从city 1到city n有很多条路
每条路的载重为这条路中最小载重街道的载重
不管从哪条路走货车的weight都不能超过这条路的载重

为了达到经济效益,要找出载重最大的一条路

解题思路:
dijkstra变形
每次找出到达某个city最大的载重

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 1000 + 5;
int Map[maxn][maxn];
int weight[maxn];
bool vis[maxn];
int n, m;

void Dijkstra(void);

int main()
{
// freopen("in.txt", "r", stdin);
    int T;

    cin>>T;
    int scenarios = 0;
    while (T--) {
        memset(vis, false, sizeof(vis));
        ++scenarios;
        cout<<"Scenario #"<<scenarios<<":"<<endl;

        cin>>n>>m;
        for (int i=1; i<=n; ++i) {
            for (int j=1; j<=n; ++j) {
                Map[i][j] = 0;
            }
        }
        int s, e, val;
        for (int i=0; i<m; ++i) {
            scanf("%d%d%d", &s, &e, &val);
            Map[s][e] = Map[e][s] = val;
        }
        Dijkstra();
        cout<<weight[n]<<endl;
        cout<<endl;
    }
    return 0;
}

void Dijkstra(void)
{
    weight[1] = 0;
    for (int i=2; i<=n; ++i) {
        weight[i] = Map[1][i];
    }
    vis[1] = true;
    for (int i=2; i<=n; ++i) {
        int t;
        int Max = -1;
        for (int j=2; j<=n; ++j) {
            if (!vis[j] && Max < weight[j]) {
                t = j;
                Max = weight[j];
            }
        }
        vis[t] = true;
        for (int j=2; j<=n; ++j) {
            if (!vis[j]) {
                Max = weight[t];
                if (Max > Map[t][j]) {
                    Max = Map[t][j];
                }
                if (weight[j] < Max) {
                    weight[j] = Max;
                }
            }
        }
    }
}

3、POJ 3767 I Wanna Go Home

题意:
Mr. M starts from city 1 and his target is city 2

city 1的leader总为1,city 2的leader总为2
And your route should contain at most 1 road which connects two cities of different camp

所以只能从camp1到camp2
不能从camp2到camp1

解题思路:
先建双向路
然后修改为只能从camp1到camp2的单向路,用dijkstra解决

心得:
RE一般就是数组越界或除零,一定要细心去找
注意没有赋初值的变量,它很可能造成数组越界,然后就顺理成章的RE了,而你却无论如何都找不出来

为了保险起见
我以后写 dijkstra 一定要写成下面这样,这是血的教训…

if (Min == INF) {
    break;
}
vis[t] = true;
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 600 + 5;
int G[maxn][maxn];
bool vis[maxn];
int dis[maxn];
int N, M;
int leader[maxn];

void Dijkstra(void);

int main()
{
// freopen("in.txt", "r", stdin);
    while (scanf("%d", &N) && N != 0) {
        memset(vis, false, sizeof(vis));
        scanf("%d", &M);
        for (int i=1; i<=N; ++i) {
            for (int j=1; j<=N; ++j) {
                if (i == j) {
                    G[i][j] = 0;
                } else {
                    G[i][j] = INF;
                }
            }
        }
        int A, B, T;
        for (int i=0; i<M; ++i) {
            scanf("%d%d%d", &A, &B, &T);
            G[A][B] = G[B][A] = T;
        }
        for (int i=1; i<=N; ++i) {
            scanf("%d", &leader[i]);
        }
        for (int i=1; i<=N; ++i) {
            for (int j=1; j<=N; ++j) {
                if (leader[i] == 1 && leader[j] == 2) {
                    G[j][i] = INF;
                }
                if (leader[i] == 2 && leader[j] == 1) {
                    G[i][j] = INF;
                }
            }
        }
        Dijkstra();
        if (dis[2] != INF) {
            printf("%d\n", dis[2]);
        } else {
            printf("-1\n");
        }
    }
    return 0;
}

void Dijkstra(void)
{
    for (int i=2; i<=N; ++i) {
        dis[i] = G[1][i];
    }
    for (int i=1; i<N; ++i) {
        int Min = INF;
        int t;
        for (int j=2; j<=N; ++j) {
            if (!vis[j] && dis[j] < Min) {
                Min = dis[j];
                t = j;
            }
        }
        if (Min == INF) {
            break;
        }
        vis[t] = true;
        for (int j=2; j<=N; ++j) {
            if (!vis[j] && dis[j] > (dis[t]+G[t][j])) {
                dis[j] = dis[t] + G[t][j];
            }
        }
    }
}

4、兔子与樱花

Description

很久很久之前,森林里住着一群兔子。有一天,兔子们希望去赏樱花,但当他们到了上野公园门口却忘记了带地图。现在兔子们想求助于你来帮他们找到公园里的最短路。
Input
输入分为三个部分。
第一个部分有P+1行(P<30),第一行为一个整数P,之后的P行表示上野公园的地点。
第二个部分有Q+1行(Q<50),第一行为一个整数Q,之后的Q行每行分别为两个字符串与一个整数,表示这两点有直线的道路,并显示二者之间的矩离(单位为米)。

Output
输出有R行,分别表示每个路线最短的走法。其中两个点之间,用->(矩离)->相隔。

Sample Input

6
Ginza
Sensouji
Shinjukugyoen
Uenokouen
Yoyogikouen
Meijishinguu
6
Ginza Sensouji 80
Shinjukugyoen Sensouji 40
Ginza Uenokouen 35
Uenokouen Shinjukugyoen 85
Sensouji Meijishinguu 60
Meijishinguu Yoyogikouen 35
2
Uenokouen Yoyogikouen
Meijishinguu Meijishinguu

Sample Output

Uenokouen->(35)->Ginza->(80)->Sensouji->(60)->Meijishinguu->(35)->Yoyogikouen
Meijishinguu

题意:
求最短路+打印路径

解题思路:
找到到达每个点的最短路,同时记录使它成为最短路的前一个点

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>

using namespace std;

const int INF = 0x3f3f3f3f;
char s[35][50];
int G[35][35];
char t1[50], t2[50];
bool vis[50];
int dis[50];
int P;
int father[50];
int flag[50];

int Search(char s[]);

void Dijkstra(int a, int b);

int main()
{
// freopen("in.txt", "r", stdin);
    scanf("%d", &P);
    for (int i=0; i<P; ++i) {
        scanf("%s", s[i]);
    }
    for (int i=0; i<P; ++i) {
        for (int j=0; j<P; ++j) {
            if (i == j) {
                G[i][j] = 0;
            } else {
                G[i][j] = INF;
            }
        }
    }
    int Q;
    scanf("%d", &Q);
    int n;
    for (int i=0; i<Q; ++i) {
        scanf("%s%s%d", t1, t2, &n);
        int x = Search(t1);
        int y = Search(t2);
        G[x][y] = G[y][x] = n;
    }
    int R;
    scanf("%d", &R);
    for (int i=0; i<R; ++i) {
        scanf("%s%s", t1, t2);
        int x = Search(t1);
        int y = Search(t2);
        if (x == y) {
            printf("%s\n", s[x]);
        } else {
            Dijkstra(x, y);
            father[x] = x;
            int t = y;
            int num[50];
            int Count = 0;
            while (father[t] != t) {
                num[Count] = t;
                ++Count;
                t = father[t];
            }
            num[Count] = x;
            printf("%s", s[x]);
            for (int j=Count-1; j>=0; --j) {
                printf("->(%d)->%s", G[num[j]][num[j+1]], s[num[j]]);
            }
            printf("\n");
        }
    }
    return 0;
}

int Search(char x[])
{
    for (int i=0; i<P; ++i) {
        if (strcmp(x, s[i]) == 0) {
            return i;
        }
    }
    return 0;
}

void Dijkstra(int a, int b)
{
    memset(flag, false, sizeof(flag));
    memset(vis, false, sizeof(vis));
    vis[a] = true;
    for (int i=0; i<P; ++i) {
        if (i != a) {
            dis[i] = G[a][i];
        }
    }
    for (int i=0; i<P; ++i) {
        int Min = INF;
        int t;
        for (int j=0; j<P; ++j) {
            if (!vis[j] && Min > dis[j]) {
                Min = dis[j];
                t = j;
            }
        }
        vis[t] = true;
        if (!flag[t]) {
            father[t] = a;
        }
        if (t == b) {
            return;
        }
        for (int j=0; j<P; ++j) {
            if (!vis[j] && dis[j] > dis[t] + G[t][j]) {
                dis[j] = dis[t] + G[t][j];
                flag[j] = true;
                father[j] = t;
            }
        }
    }
}
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int INF = 0x3f3f3f3f;
char s[35][50];
int G[35][35];
char t1[50], t2[50];
bool vis[50];
int dis[50][50];
int P;
int father[50][50];

int Search(char s[]);

void Floyd(void);

int main()
{
// freopen("in.txt", "r", stdin);
    scanf("%d", &P);
    for (int i=0; i<P; ++i) {
        scanf("%s", s[i]);
    }
    for (int i=0; i<P; ++i) {
        for (int j=0; j<P; ++j) {
            if (i == j) {
                G[i][j] = 0;
                father[i][j] = -1;
                dis[i][j] = 0;
            } else {
                G[i][j] = INF;
                dis[i][j] = INF;
            }
        }
    }
    int Q;
    scanf("%d", &Q);
    int n;
    for (int i=0; i<Q; ++i) {
        scanf("%s%s%d", t1, t2, &n);
        int x = Search(t1);
        int y = Search(t2);
        G[x][y] = G[y][x] = n;
    }
    Floyd();
    int R;
    scanf("%d", &R);
    for (int i=0; i<R; ++i) {
        scanf("%s%s", t1, t2);
        int x = Search(t1);
        int y = Search(t2);
        if (x == y) {
            printf("%s\n", s[x]);
        } else {
            int num[50];
            int Count = 0;
            father[x][x] = -1;
            while (father[x][y] != -1) {
                num[Count] = y;
                ++Count;
                y = father[x][y];
            }
            num[Count] = x;
            printf("%s", s[x]);
            for (int j=Count-1; j>=0; --j) {
                printf("->(%d)->%s", G[num[j]][num[j+1]], s[num[j]]);
            }
            printf("\n");
        }
    }
    return 0;
}

int Search(char x[])
{
    for (int i=0; i<P; ++i) {
        if (strcmp(x, s[i]) == 0) {
            return i;
        }
    }
    return 0;
}

void Floyd(void)
{
    for (int k=0; k<P; ++k) {
        memset(vis, false, sizeof(vis));
        for (int i=0; i<P; ++i) {
            int Min = INF;
            int t;
            for (int j=0; j<P; ++j) {
                if (!vis[j] && dis[k][j] < Min) {
                    Min = dis[k][j];
                    t = j;
                }
            }
            if (Min == INF) {
                break;
            }
            vis[t] = true;
            for (int j=0; j<P; ++j) {
                if (!vis[j] && dis[k][t] + G[t][j] < dis[k][j]) {
                    dis[k][j] = dis[k][t] + G[t][j];
                    father[k][j] = t;
                }
            }
        }
    }
}

5、POJ 3259 Wormholes

题意:
farms comprises N (1 ≤ N ≤ 500) fields
有M条路,路的一端为S,另一端为E,从S到E和从E到S花费的时间都为T

又有W条路,起点为虫洞S,终点为E,穿越回去花费的时间为T

he wants to do the following:
start at some field,
travel through some paths and wormholes,
and return to the starting field a time before his initial departure.
Perhaps he will be able to meet himself :)

解题思路:
用Bellman-Ford算法找一下有没有负权环

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

struct Edge {
    int x, y;
    int val;
};

const int INF = 10000 + 5;
const int maxn = 500 + 5;
int dis[maxn];
int Count;
int N, M, W;
Edge edge[6000];

int Bellman_Ford(void);

int main()
{
// freopen("in.txt", "r", stdin);
    int F;

    while (cin>>F) {
        while (F--) {
            Count = 0;
            cin>>N>>M>>W;
            int S, E, T;
            for (int i=0; i<M; ++i) {
                cin>>S>>E>>T;
                edge[Count].x = S;
                edge[Count].y = E;
                edge[Count].val = T;
                ++Count;
                edge[Count].x = E;
                edge[Count].y = S;
                edge[Count].val = T;
                ++Count;
            }
            for (int i=0; i<W; ++i) {
                cin>>S>>E>>T;
                edge[Count].x = S;
                edge[Count].y = E;
                edge[Count].val = -T;
                ++Count;
            }
            if (Bellman_Ford()) {
                cout<<"YES"<<endl;
            } else {
                cout<<"NO"<<endl;
            }
        }
    }
    return 0;
}

int Bellman_Ford(void)
{
    for (int i=1; i<=N; ++i) {
        dis[i] = INF;
    }
    int flag;
    for (int i=0; i<N-1; ++i) {
        flag = 0;
        for (int j=0; j<Count; ++j) {
            if (dis[edge[j].y] > dis[edge[j].x] + edge[j].val) {
                dis[edge[j].y] = dis[edge[j].x] + edge[j].val;
                flag = 1;
            }
        }
        if (flag == 0) {
            break;
        }
    }
    for (int i=0; i<Count; ++i) {
        if (dis[edge[i].y] > dis[edge[i].x] + edge[i].val) {
            return 1;
        }
    }
    return 0;
}

你可能感兴趣的:(最短路)