P1339 [USACO09OCT]Heat Wave G

题目传送门

一、图的存储方式总结

存图可以三种办法:
(1)点到点:邻接矩阵
(2)点+点的出边:邻接表
(3)只保存边:Edge结构体

适合场景:
邻接矩阵
(1)要判断任意两顶点是否有边无边就很容易了;
(2)要知道某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和;
(3)求顶点vi的所有邻接点就是将矩阵中第i行元素扫描一遍,g[i][j]1就是邻接点;
而有向图讲究入度和出度,顶点vi的入度为1,正好是第i列各数之和。顶点vi的出度为2,即第i行的各数之和。

邻接表
邻接矩阵是不错的一种图存储结构,但是,对于边数相对顶点较少的图,这种结构存在对存储空间的极大浪费。因此,找到一种数组与链表相结合的存储方法称为邻接表。
(1)快速知道从某个点引出多少条边
(2)无法快速知道两个点之间是否有边
(3)如果只关心枚举每条边,需要先枚举每个点,再二次循环找到每条边,不如按结构体存方便

二、Bellman_Ford+结构体

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 2510;          //结点数
const int M = 6200 * 2 + 10; //边数


struct Edge {
    int a, b, c;
} edges[M];

int n, m; // n个结点,m条边
int s, t; //起点,终点
int d[N]; //距离数组

void bellman_ford() {
    memset(d, 0x3f, sizeof d);
    d[s] = 0;

    for (int i = 1; i < n; i++)
        for (int j = 0; j < 2 * m; j++) {
            Edge e = edges[j];
            d[e.b] = min(d[e.b], d[e.a] + e.c);
        }
}

int main() {
    cin >> n >> m >> s >> t;
    for (int i = 0; i < m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        edges[i] = {a, b, c}, edges[m + i] = {b, a, c};
    }
    bellman_ford();

    cout << d[t] << endl;
    return 0;
}

三、Bellman_Ford+邻接表

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 2510;          //结点数
const int M = 6200 * 2 + 10; //边数

//邻接表
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}

int n, m; // n个结点,m条边
int s, t; //起点,终点
int d[N]; //距离数组

void bellman_ford() {
    memset(d, 0x3f, sizeof d);
    d[s] = 0;
    int T = n - 1;                              //常规的Bellman_Ford是执行n-1次
    while (T--) {                               //松驰n-1次
        for (int k = 1; k <= n; k++)            //枚举1~n节点
            for (int i = h[k]; ~i; i = ne[i]) { //二层循环枚举每个节点的出边
                int j = e[i];
                d[j] = min(d[j], d[k] + w[i]);
            }
    }
}

int main() {
    memset(h, -1, sizeof h);
    cin >> n >> m >> s >> t;
    for (int i = 0; i < m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c), add(b, a, c);
    }
    bellman_ford();
    cout << d[t] << endl;
    return 0;
}

四、SPFA

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 2510;          //结点数
const int M = 6200 * 2 + 10; //边数

int n, m; // n个结点,m条边
int s, t; //起点,终点

//邻接表
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int d[N];   //最短距离数组
bool st[N]; //是不是进过队列

// spfa模板
void spfa(int start) {
    queue<int> q;
    //将所有距离初始化为无穷大
    memset(d, 0x3f, sizeof d);
    //出发点的距离清零
    d[start] = 0;

    q.push(start);    //出发点入队列
    st[start] = true; //出发点标识已使用

    while (q.size()) {
        int t = q.front();
        q.pop();
        st[t] = false;
        for (int i = h[t]; ~i; i = ne[i]) {
            int j = e[i];
            if (d[j] > d[t] + w[i]) {
                d[j] = d[t] + w[i];
                if (!st[j]) {
                    st[j] = true;
                    q.push(j);
                }
            }
        }
    }
}

int main() {
    memset(h, -1, sizeof h);
    cin >> n >> m >> s >> t;
    for (int i = 0; i < m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c), add(b, a, c);
    }
    spfa(s);
    cout << d[t] << endl;
    return 0;
}

五、Dijkstra

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;

const int N = 2510;          //结点数
const int M = 6200 * 2 + 10; //边数

int n, m; // n个结点,m条边
int s, t; //起点,终点

typedef pair<int, int> PII;
//邻接表
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int d[N];   //最短距离数组
bool st[N]; //是不是进过队列

//迪杰斯特拉
void dijkstra(int start) {
    memset(d, 0x3f, sizeof d);                        //初始化距离为无穷大
    memset(st, 0, sizeof st);                         //初始化为未出队列过
    d[start] = 0;                                     //出发点距离0
    priority_queue<PII, vector<PII>, greater<PII>> q; //小顶堆
    q.push({0, start});                               //出发点入队列
    while (q.size()) {
        auto t = q.top();
        q.pop();
        int u = t.second;
        if (st[u]) continue;
        st[u] = true;
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (d[j] > d[u] + w[i]) {
                d[j] = d[u] + w[i];
                q.push({d[j], j});
            }
        }
    }
}

int main() {
    memset(h, -1, sizeof h);
    cin >> n >> m >> s >> t;
    for (int i = 0; i < m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c), add(b, a, c);
    }
    dijkstra(s);
    cout << d[t] << endl;
    return 0;
}

posted @   糖豆爸爸  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2020-04-07 Centos7 安装mysql-8.0.13(rpm)
Live2D
点击右上角即可分享
微信分享提示