最短路

最短路

算法讲解

spfa

个人曾经是个巨菜巨菜的oier,所以对又好写,又不用管负权圈的spfa情有独钟,所以导致到现在写最短路还都是用的spfa。因为有的时候vector实在太慢了,所以我就把邻接表打了个包~这样用着舒服一点。

普通spfa

关于spfa的原理啥的,别的大佬们写的太好了,我就不献丑了~这里还是推荐一个大佬的spfa原理讲解
ps:虽然各路大佬都在声讨spfa的复杂度很差,常数很高啥的,但是架不住好写哇orz。各路大佬轻喷啊~

模板
class short_road {

protected:
private:

    struct rec {
        int u, v, next;
        int w;
    } edge[maxn];

    bool vis[maxn];
    int dis[maxn];
    int cnt[maxn], head[maxn];
    int tot,n;

public:

    inline void init(int _n) {
        tot = 0;
        clr(edge);
        cld(head);
        clr(vis);
        clx(dis);
        clr(cnt);
        n = _n;
    }


    inline void Addedge(int u, int v, int w) {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot;
        tot++;
    }

    inline bool relax(rec e) {
        if (dis[e.u] + e.w < dis[e.v]) {
            dis[e.v] = dis[e.u] + e.w;
            return true;
        } else {
            return false;
        }
    }

    inline bool spfa(int x) {

        queue<int> data;
        data.push(x);
        dis[x] = 0;
        vis[x] = true;
        cnt[x]++;
        while (!data.empty()) {
            int u = data.front();
            data.pop();
            vis[u] = false;
            for (int i = head[u]; i != -1; i = edge[i].next) {
                rec e = edge[i];
                if (relax(e)) {
                    if (++cnt[e.v] > n) return true;
                    if (!vis[e.v]) {
                        vis[e.v] = true;
                        data.push(e.v);
                    }
                }
            }
        }
        return false;
    }
    inline int dist(int t){
        return dis[t];
    }
} sr;
SLF和LLF优化

说spfa肯定要说两个优化啦~有的时候又要有负权圈,又要快,就只能用SLF和LLF两种优化啦~不过如果没有负权圈,但是普通spfa不能过的话,就别用这两个优化了,直接dijkstra就完了~像上次qls出的女生赛题,不管你spfa再怎么优化也都过不了,只能稳稳妥妥写dijkstra咯~
再说两种优化:
SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾。
LLL:Large Label Last 策略,设队首元素为i,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i出对进行松弛操作。 SLF 可使速度提高 15 ~ 20%;SLF + LLL 可提高约 50%。

模板
class short_road {
protected:
private:
    struct rec {
        int v, next, cap;
    } edge[maxn];

    int len,n;
    int dis[maxn / 4], head[maxn / 4], cnt[maxn / 4];
    bool vis[maxn / 4];
public:

    inline void init(int _n) {
        clr(edge);
        cld(head);
        clx(dis);
        clr(vis);
        clr(cnt);
        len = 0;
        n = _n;
    }

    inline void Addedge(int from, int to, int cap) {
        edge[len].v = to;
        edge[len].cap = cap;
        edge[len].next = head[from];
        head[from] = len++;
    }

    inline bool spfa(int s) {
        dis[s] = 0;
        vis[s] = true;
        deque<int> que;
        que.push_front(s);
        while (!que.empty()) {
            int k = que.front();
            que.pop_front();
            vis[k] = false;
            cnt[k]++;
            if (cnt[k] > n) return false;

            for (int i = head[k]; i != -1; i = edge[i].next) {
                if (dis[edge[i].v] > dis[k] + edge[i].cap) {
                    dis[edge[i].v] = dis[k] + edge[i].cap;
                    if (que.empty()) {
                        que.push_front(edge[i].v);
                        vis[edge[i].v] = true;
                    } else if (!vis[edge[i].v]) {
                        if (dis[edge[i].v] > dis[que.front()]) {
                            que.push_back(edge[i].v);
                        } else {
                            que.push_front(edge[i].v);
                        }
                        vis[edge[i].v] = true;
                    }
                }
            }
        }
        return true;
    }
    inline int dist(int t){
        return dis[t];
    }
} sr;

dijkstra

虽然喜欢用spfa,但是dijkstra还是肯定要会的啦,毕竟有些毒瘤出题人就很喜欢卡spfa是吧~算法原理我就不写了,这里按照惯例还是推荐一篇大佬写的dijkstra算法原理
当然啦~dijkstra的模板还是要贴一下的(肯定是优先队列优化的,非优化的我就不说了)。

模板
class short_road {
protected:
private:
    struct rec {
        int v, w;

        explicit rec(int _v = 0, int _w = 0) {
            v = _v;
            w = _w;
        }

        bool operator<(const rec &a) const {
            if (w == a.w) return v < a.v;
            else return w < a.w;
        }
    };

    struct rec1 {
        int u, v, next;
        int w;
    } edge[maxn];

    int dis[maxn], n,tot,head[maxn];
public:

    inline void init(int _n) {
        tot = 0;
        clr(edge);
        cld(head);
        clx(dis);
        n = _n;
    }

    inline void Addedge(int u, int v, int w) {
        edge[tot].u = u;
        edge[tot].v = v;
        edge[tot].w = w;
        edge[tot].next = head[u];
        head[u] = tot;
        tot++;
    }

    inline bool relax(rec1 e) {
        if (dis[e.u] + e.w < dis[e.v]) {
            dis[e.v] = dis[e.u] + e.w;
            return true;
        } else {
            return false;
        }
    }

    inline void Dijkstra(int s) {
        dis[s] = 0;
        priority_queue<rec> q;
        q.push(rec(s, dis[s]));
        while (!q.empty()) {
            rec u = q.top();
            q.pop();
            for (int i = head[u.v]; i != -1; i = edge[i].next) {
                rec1 e = edge[i];
                if (relax(e)) {
                    q.push(rec(e.v, dis[e.w]));
                }
            }
        }
    }

    inline int dist(int t) {
        return dis[t];
    }
} sr;

题解

又到了喜闻乐见的kuangbin系列题解了~

POJ - 2387 Til the Cows Come Home

传送门:POJ - 2387

题意

有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离。

题解

直接单源最短路跑就ok了~模板题~
ps:dijkstra要判重边,但spfa就不用,也许这就是我这个菜鸡为毛爱用spfa吧

ac代码
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e4 + 7;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))


struct rec {
    int v;
    int w;

    rec(int _v, int _w) {
        v = _v;
        w = _w;
    }
};

vector<rec> vec[maxn];
bool vis[maxn];
int dis[maxn];
int n, t, u, v, w;

void spfa(int x) {
    clr(vis);
    for (int i = 1; i <= n; ++i) {
        dis[i] = inf;
    }

    queue<int> data;
    data.push(x);
    dis[x] = 0;
    while (!data.empty()) {
        int u = data.front();
        data.pop();
        vis[u] = false;
        for (int i = 0; i < vec[u].size(); ++i) {
            int v = vec[u][i].v;
            int w = vec[u][i].w;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!vis[v]) {
                    vis[v] = true;
                    data.push(v);
                }
            }
        }
    }


}

int main() {

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif


    while (~scanf("%d%d", &t, &n)) {
        clr(vec);
        for (int i = 0; i < t; i++) {
            scanf("%d%d%d", &u, &v, &w);
            vec[u].push_back(rec(v, w));
            vec[v].push_back(rec(u, w));
        }

        spfa(1);
        printf("%d\n", dis[n]);
    }
    return 0;
}

POJ - 2253 Frogger

传送门:POJ - 2253

题意

有一条小河,河中有青蛙a和青蛙b。青蛙a呆在石头1上,青蛙b呆在石头2上,已知河中总共有n块石头,编号为1~n,已知所有石头的坐标。现在青蛙a想去找青蛙b玩,求青蛙a所需的最小跳跃距离。

题解

就把所有的两点之间距离求一下就ok了~然后直接跑最短路就ok了~

ac代码
#include <vector>
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6 + 7;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x));
int n;
double dis[maxn];
int vis[maxn];

struct rec {
    int x, y;
} a[maxn];

double distance1(int x, int y) {
    int p = abs(a[x].x - a[y].x);
    int q = abs(a[x].y - a[y].y);
    return sqrt((double) p * p + q * q);
}


void spfa(int x) {
    clr(vis);
    for (int i = 1; i <= n; i++) {
        dis[i] = inf;
    }

    queue<int> data;
    dis[x] = 0;
    data.push(x);
    while (!data.empty()) {
        int u = data.front();
        vis[u] = false;
        data.pop();
        for (int i = 1; i <= n; i++) {
            if (i != u) {
                if (dis[i] > max(dis[u], distance1(u, i))) {
                    dis[i] = max(dis[u], distance1(u, i));
                    if (!vis[i]) {
                        vis[i] = true;
                        data.push(i);
                    }
                }
            }
        }
    }
}

int main() {

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    int num = 0;
    while (~scanf("%d", &n) && n) {
        for (int i = 1; i <= n; i++) {
            scanf("%d%d", &a[i].x, &a[i].y);
        }
        spfa(1);
        printf("Scenario #%d\n", ++num);
        printf("Frog Distance = %.3lf\n", dis[2]);
        cout << endl;
    }

    return 0;
}

POJ - 1797 Heavy Transportation

传送门: POJ - 1797

题意

有n个城市,m条道路,在每条道路上有一个承载量,现在要求从1到n城市最大承载量,而最大承载量就是从城市1到城市n所有通路上的最大承载量

题解

还是最短路的模板,就是改成求最大化最小值~那就把板子一套,完活~

ac代码
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e5 + 7;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x));

struct rec {
    int v, w;

    rec(int _v, int _w) {
        v = _v;
        w = _w;
    }
};

vector<rec> vec[maxn];

bool vis[maxn];
int dis[maxn];
int n, m, u, v, w;

void spfa(int x) {
    clr(vis);
    clr(dis);

    queue<int> data;
    data.push(x);
    dis[1] = inf;
    while (!data.empty()) {
        int u = data.front();
        data.pop();
        vis[u] = false;
        for (int i = 0; i < vec[u].size(); ++i) {
            int v = vec[u][i].v;
            int w = vec[u][i].w;
            if (dis[v] < min(dis[u], w)) {
                dis[v] = min(dis[u], w);
                if (!vis[v]) {
                    vis[v] = true;
                    data.push(v);
                }
            }
        }
    }


}


int main() {

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif

    int T;
    scanf("%d",&T);
    int num = 0;
    while (T--) {
        clr(vec);
        scanf("%d%d",&n,&m);
        while (m--) {
            scanf("%d%d%d",&u,&v,&w);
            vec[u].push_back(rec(v, w));
            vec[v].push_back(rec(u, w));
        }
        spfa(1);
        printf("Scenario #%d:\n%d\n\n",++num,dis[n]);
    }

    return 0;
}

POJ - 3268 Silver Cow Party

传送门:POJ - 3268

题意

有编号为1-N的牛,它们之间存在一些单向的路径。给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求这些牛中所花的最长的来回时间是多少。

题解

去和返回,求两次,返回好求,直接用目标牛跑spfa。去咋求呢,就可以直接把所有边全部反过来建图,然后还是用目标牛跑spfa,这样就求出来每头牛到目标牛的最短路啦~

ac代码
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6+7;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x));


struct rec {
    int v;
    int w;

    rec(int _v = 0, int _w = 0) {
        v = _v;
        w = _w;
    }
};

vector <rec> vec1[maxn];
vector<rec> vec2[maxn];
bool vis[maxn];
int dis1[maxn],dis2[maxn];
int n,m,x,a,b,t;

void spfa(int x,int dis[],vector<rec> vec[]) {
    clr(vis);
    for (int i = 1; i <= n; ++i) {
        dis[i] = inf;
    }

    queue<int> data;
    data.push(x);
    dis[x] = 0;
    while (!data.empty()) {
        int u = data.front();
        data.pop();
        vis[u] = false;
        for (int i = 0; i < vec[u].size(); ++i) {
            int v = vec[u][i].v;
            int w = vec[u][i].w;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!vis[v]) {
                    vis[v] = true;
                    data.push(v);
                }
            }
        }
    }
}



int main(){

#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif


    cin >> n >> m >> x;
    for(int i = 0;i < m;i++){
        cin >> a >> b >> t;
        vec1[b].push_back(rec(a,t));
        vec2[a].push_back(rec(b,t));
    }
    spfa(x,dis1,vec1);
    spfa(x,dis2,vec2);
    int ans = -inf;
    for(int i = 1;i <= n;i++){
        ans = max(dis1[i] + dis2[i],ans);
    }

    cout << ans<< endl;

    return 0;
}

POJ - 1860 Currency Exchange

传送门:POJ - 1860

题意

给定N种货币,某些货币之间可以相互兑换,现在给定一些兑换规则,问能否从某一种货币开始兑换,经过一些中间货币之后,最后兑换回这种货币,并且得到的钱比之前的多。

题解

这题很明显就是spfa判断负环,也不能叫负环哈,就是求最长路,然后判断正环,直接spfa模板一套,完事。

ac代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6 + 7;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926

struct rec {
    int v;
    double r, c;

    explicit rec(int _v = 0, double _r = 0, double _c = 0) {
        v = _v;
        r = _r;
        c = _c;
    }
};

vector<rec> vec[maxn];

bool vis[maxn];
double dis[maxn];
int cnt[maxn];
int n, m, s;

bool spfa(int x, double mon) {
    clr(vis);
    clr(dis);

    queue<int> data;
    data.push(x);
    for (int i = 0; i < n + 1; i++) {
        dis[i] = -inf;
    }
    dis[x] = mon;
    cnt[x]++;
    vis[x] = true;
    while (!data.empty()) {
        int u = data.front();
        data.pop();
        vis[u] = false;
        for (int i = 0; i < vec[u].size(); ++i) {
            int v = vec[u][i].v;
            double w = (dis[u] - vec[u][i].c) * vec[u][i].r;
            if (dis[v] < w) {
                dis[v] = w;
                cnt[v]++;
                if (cnt[v] > n) return false;
                if (!vis[v]) {
                    vis[v] = true;
                    data.push(v);
                }
            }
        }
    }
    return true;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    double v;
    int a, b;
    double rab, cab, rba, cba;

    cin >> n >> m >> s >> v;

    for (int i = 0; i < m; i++) {
        cin >> a >> b >> rab >> cab >> rba >> cba;
        vec[a].emplace_back(rec(b, rab, cab));
        vec[b].emplace_back(rec(a, rba, cba));
    }
    if (spfa(s, v)) {
        cout << "NO" << endl;
    } else {
        cout << "YES" << endl;
    }
    return 0;
}

POJ - 3259 Wormholes

传送门:POJ - 3259

题意

这题问是否能通过虫洞回到过去。
虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。

题解

这题同上题,也是spfa跑负权圈

ac代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6 + 7;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926

struct rec {
    int v, w;

    explicit rec(int _v = 0, int _w = 0) {
        v = _v;
        w = _w;
    }
};

bool vis[maxn];
int dis[maxn], cnt[maxn];
vector<rec> vec[maxn];
int n, m, w, u, v, t;

bool spfa(int x) {
    clr(vis);
    clr(dis);
    clr(cnt);
    for (int i = 0; i <= n; i++) {
        dis[i] = inf;
    }

    queue<int> data;
    data.push(x);
    vis[x] = true;
    dis[x] = 0;
    cnt[x]++;
    while (!data.empty()) {
        int u = data.front();
        data.pop();
        vis[u] = false;
        for (int i = 0; i < vec[u].size(); ++i) {
            int v = vec[u][i].v;
            int w = vec[u][i].w;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (++cnt[v] > n - 1) {
                    return false;
                }
                if (!vis[v]) {
                    data.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    return true;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif

    int T;
    cin >> T;
    while (T--) {
        clr(vec);
        cin >> n >> m >> w;
        for (int i = 0; i < m; i++) {
            cin >> u >> v >> t;
            vec[u].emplace_back(rec(v, t));
            vec[v].emplace_back(rec(u, t));
        }
        for (int i = 0; i < w; i++) {
            cin >> u >> v >> t;
            vec[u].emplace_back(rec(v, -t));
        }

        if (!spfa(1)) {
            cout << "YES" << endl;
        } else {
            cout << "NO" << endl;
        }

    }

    return 0;
}

POJ - 1502 MPI Maelstrom

传送门:POJ - 1502

题意

N个处理器要进行信息传递,处理器i传递信息给自己不需要时间,处理器i与处理器j之间相互传递信息的时间是一样的,不同处理器之间传递信息所需要的时间由一个矩阵的下三角给出。若矩阵对应位置为x,则说明相应的两个处理器之间无法传递信息。求从第一个处理器传递信息到其他所有处理器最少需要多少时间。

题解

这个就是直接的最短路,只要处理一下读入就ok了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e3;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926

struct rec {
    int v, w;

    rec(int _v, int _w) {
        v = _v;
        w = _w;
    }
};

vector<rec> vec[maxn];

bool vis[maxn];
int dis[maxn];
int n, m, u, v, w;

void spfa(int x) {
    clr(vis);
    clr(dis);
    for(int i = 0;i <= n;i++){
        dis[i] = inf;
    }
    queue<int> data;
    data.push(x);
    dis[x] = 0;
    vis[x] = true;
    while (!data.empty()) {
        int u = data.front();
        data.pop();
        vis[u] = false;
        for (int i = 0; i < vec[u].size(); ++i) {
            int v = vec[u][i].v;
            int w = vec[u][i].w;
            if (dis[v] > dis[u]+ w) {
                dis[v] = dis[u]+ w;
                if (!vis[v]) {
                    vis[v] = true;
                    data.push(v);
                }
            }
        }
    }


}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif

    cin >> n;
    string ch;
    for(int i = 2;i <= n;i++){
        for(int j = 1;j < i;j++){
            cin >> ch;
            if(ch != "x"){
                int w = atoi(ch.c_str());
                vec[i].push_back(rec(j,w));
                vec[j].push_back(rec(i,w));
            }

        }
    }

    spfa(1);

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

    cout << ans << endl;

    return 0;
}

POJ - 3660 Cow Contest

传送门:POJ - 3660

题意

有n头牛比赛,m种比赛结果,最后问你一共有多少头牛的排名被确定了,其中如果a战胜b,b战胜c,则也可以说a战胜c,即可以传递胜负。求能确定排名的牛的数目。

题解

这题就是传递闭包了,
G的传递闭包定义为G*=(V,E*),其中E={(i,j):图G中存在一条从i到j的路径}。
直接看代码吧~

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e6 + 7;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926

int mp[105][105];
int n,m;

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif

    while (~scanf("%d%d", &n, &m)) {
        int u, v;
        memset(mp, 0, sizeof(mp));
        for (int i = 0; i < m; i++) {
            scanf("%d %d", &u, &v);
            mp[u][v] = 1;
        }

        for (int k = 1; k <= n; k++) {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    mp[i][j] = (mp[i][j] | (mp[i][k] & mp[k][j]));
                }
            }
        }

        for (int i = 1; i <= n; i++) mp[i][i] = 0;

        int ans = 0;
        for (int i = 1; i <= n; i++) {
            int cnt = 0;
            for (int j = 1; j <= n; j++) {
                cnt += mp[i][j];
                cnt += mp[j][i];
            }
            if (cnt == n - 1) ans++;
        }

        printf("%d\n", ans);
    }
    return 0;
}

POJ - 2240 Arbitrage

传送门:POJ - 2240

题意

已知n种货币,以及m种货币汇率及方式,问能否通过货币转换,使得财富增加。

题解

这题和上面POJ - 1860几乎一样,也是spfa判断负权圈

ac代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<vector>
#include<stack>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = (int) 1e4;
const double exp = 1e-8;
typedef long long ll;
#define clr(x) memset(x,0,sizeof(x))
#define pi 3.1415926
string a[maxn];
int n, m;

int check(const string &str) {
    for (int i = 1; i <= n; i++) {
        if (str == a[i]) {
            return i;
        }
    }
}

class short_road {

protected:
private:

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

    bool vis[maxn];
    double dis[maxn];
    int cnt[maxn], head[maxn];
    int tot;

public:

    inline void init() {
        tot = 0;
        clr(edge);
        memset(head, -1, sizeof(head));
    }


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

    inline bool relax(int e) {
        if (dis[edge[e].u] * edge[e].w > dis[edge[e].v]) {
            dis[edge[e].v] = dis[edge[e].u] * edge[e].w;
            return true;
        } else {
            return false;
        }
    }

    inline bool spfa(int x) {
        clr(vis);
        clr(dis);
        clr(cnt);
        queue<int> data;
        data.push(x);
        dis[x] = 1;
        vis[x] = true;
        cnt[x]++;
        while (!data.empty()) {
            int u = data.front();
            data.pop();
            vis[u] = false;
            for (int e = head[u]; e != -1; e = edge[e].next) {
                if (relax(e)) {
                    if (++cnt[edge[e].v] > n) return true;
                    if (!vis[edge[e].v]) {
                        vis[edge[e].v] = true;
                        data.push(edge[e].v);
                    }
                }
            }
        }
        return false;
    }
} sr;

int main() {
    //std::ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif


    int T = 0;
    while (~scanf("%d", &n) && n) {
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            sr.init();
        }
        string str1, str2;
        double w;
        cin >> m;
        for (int i = 0; i < m; i++) {
            cin >> str1 >> w >> str2;
            sr.addEdge(check(str1), check(str2), w);
        }
        if (sr.spfa(1)) {
            printf("Case %d: Yes\n", ++T);
        } else {
            printf("Case %d: No\n", ++T);
        }
    }


    return 0;
}

CSU - 1808 地铁

传送门:CSU - 1808

题意

中文题我题意就不写了啊~

题解

这个题是真的很有意思呀~
这个题有很多种写法,有拆边写的,有优先队列加bfs(总觉得就是写了个spfa),有加边的dijkstra,各种写法都有。
我自己是用map做映射写的,还是很有意思的题~
ps:我这个写法确实有点慢,应该是这些写法里最慢得了。

ac代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <cmath>
#include <ctime>
#include <set>
#include <map>

using namespace std;
typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll mxll = 0x3f3f3f3f3f3f3f3f;
const int maxn = (int) 4e5 + 7;
const double eps = 1e-10;
const ll mod = (int) 1e9 + 7;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define clr(x) memset(x,0,sizeof(x))
#define clx(x) memset(x,63,sizeof(x))
#define cln(x) memset(x,-64,sizeof(x))
#define pi 3.1415926


struct rec {
    ll v, w, c;

    rec(ll _v, ll _w, ll _c) {
        v = _v;
        w = _w;
        c = _c;
    }
};

struct node {
    ll w, id;
};

vector<rec> vec[maxn];

bool vis[maxn];
map<ll, ll> dis[maxn];
ll n, m, u, v, w, c;

void spfa(ll x) {
    clr(vis);
    for (int i = 0; i <= n; i++)dis[i].clear();


    queue<ll> data;
    data.push(x);
    dis[x][0] = 0;
    while (!data.empty()) {
        ll u = data.front();
        data.pop();
        vis[u] = false;
        for (auto &i : vec[u]) {
            ll v = i.v;
            ll w = 0;
            for (auto &iter : dis[u]) {
                if (u == x) {
                    w = i.w;
                } else {
                    w = i.w + abs(iter.first - i.c);
                }
                if (dis[v][i.c] > w + iter.second || (dis[v][i.c] == 0 && v != x)) {
                    dis[v][i.c] = iter.second + w;
                    if (!vis[v]) {
                        vis[v] = true;
                        data.push(v);
                    }
                }
            }
        }
    }


}

int main() {
    std::ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif

    while (~scanf("%lld%lld", &n, &m)) {
        clr(vec);
        for (int i = 0; i < m; i++) {
            scanf("%lld%lld%lld%lld", &u, &v, &c, &w);
            vec[u].emplace_back(rec(v, w, c));
            vec[v].emplace_back(rec(u, w, c));
        }

        spfa(1);
        ll ans = mxll;
        for (auto &iter : dis[n]) {
            ans = min(iter.second, ans);
        }
        printf("%lld\n", ans);

    }

    return 0;
}

小计

自己是真的懒。。。老早老早就写完的题,一直拖到这个时候才写博客orz。忘大家捧场啦~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值