基础算法——搜索与图论

搜索与图论

图的存储方式

2、最短路问题

最短路问题可以分为单源最短路问题和多源最短路问题,单源最短路问题就是求出从点1->n的最短距离,而多源最短路问题就是求出从点i->j的最短距离。单源最短路问题还可以分为正权边的单源最短路问题和负权边的单源最短路问题。具体算法和时间复杂度如下图:

2.1、Dijkstra算法(朴素版)


算法模板:

cpp 复制代码
#include <iostream>
#include <cstring>

using namespace std;
const int N = 510;
int g[N][N], d[N];
int n, m;
bool st[N];

int dijkstra()
{
    memset(d, 0x3f, sizeof d);
    d[1] = 0;
    for (int i = 0; i < n; i++)
    {
        int t = -1;
        for (int j = 1; j <= n; j++)
            if (!st[j] && (t == -1 || d[t] > d[j]))
                t = j;
        st[t] = true;
        for (int j = 1; j <= n; j++)
            d[j] = min(d[j], d[t] + g[t][j]);
    }
    return d[n] == 0x3f3f3f3f ? -1 : d[n];
}

int main()
{
    cin >> n >> m;
    memset(g, 0x3f, sizeof g);
    while (m--)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        g[a][b] = min(g[a][b], c);
    }
    cout << dijkstra() << endl;
    return 0;
}

2.2、Dijkstra算法(堆优化版)

下面来看看如何优化:

算法模板:

cpp 复制代码
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<int, int> PII;
const int N = 1.5e5+10;
int h[N], e[N], w[N], ne[N], idx;
int n, m, d[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

int dijkstra()
{
    memset(d, 0x3f, sizeof d);
    d[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});
    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();
        int ver = t.second, dis = t.first;
        if (st[ver]) continue;
        st[ver] = true;
        for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (d[j] > dis + w[i])
            {
                d[j] = dis + w[i];
                heap.push({d[j], j});
            }
        }
    }
    return d[n] == 0x3f3f3f3f ? -1 : d[n];
}

int main()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);
    while (m--)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }
    cout << dijkstra() << endl;
    return 0;
}

2.3、Bellman-Ford算法


代码模板:

cpp 复制代码
#include <iostream>
#include <cstring>

using namespace std;
const int N = 510, M = 10010;
int n, m, k;
int d[N], backup[N];

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

void bellman_ford()
{
    memset(d, 0x3f, sizeof d);
    d[1] = 0;
    for (int i = 0; i < k; i++)
    {
        memcpy(backup, d, sizeof d);
        for (int j = 0; j < m; j++)
        {
            auto e = edges[j];
            d[e.b] = min(d[e.b], backup[e.a] + e.w);
        }
    }
}

int main()
{
    cin >> n >> m >> k;
    for (int i = 0; i < m; i++)
    {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        edges[i] = {a, b, w};
    }
    bellman_ford();
    if (d[n] > 0x3f3f3f3f / 2) cout << "impossible" << endl;
    else cout << d[n] << endl;
    return 0;
}

2.4、SPFA求最短路

代码模板:

cpp 复制代码
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
const int N = 1e5+10;
int n, m;
int h[N], e[N], w[N], ne[N], idx;
int d[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void spfa()
{
    memset(d, 0x3f, sizeof d);
    d[1] = 0;
    queue<int> q;
    q.push(1);
    st[1] = true;
    while (q.size())
    {
        auto t = q.front();
        q.pop();
        st[t] = false;
        for (int i = h[t]; i != -1; 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()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);
    while (m--)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }
    spfa();
    if (d[n] == 0x3f3f3f3f) cout << "impossible" << endl;
    else cout << d[n] << endl;
    return 0;
}

2.5、SPFA判负环

cpp 复制代码
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
const int N = 2010, M = 10010;
int h[N], e[M], w[M], ne[M], idx;
int n, m;
int d[N], cnt[N];
bool st[N];

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

bool spfa()
{
    queue<int> q;
    for (int i = 1; i <= n; i++)
    {
        q.push(i);
        st[i] = true;
    }
    while (q.size())
    {
        auto t = q.front();
        q.pop();
        st[t] = false;
        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (d[j] > d[t] + w[i])
            {
                d[j] = d[t] + w[i];
                cnt[j] = cnt[t] + 1;
                if (cnt[j] >= n) return true;
                if (!st[j])
                {
                    st[j] = true;
                    q.push(j);
                }
            }
        }
    }
    return false;
}

int main()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);
    while (m--)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c);
    }
    if (spfa()) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}

2.6、Floyd算法

cpp 复制代码
#include <iostream>
#include <cstring>

using namespace std;
const int N = 210, INF = 0x3f3f3f3f;
int d[N][N];
int n, m, k;

void floyd()
{
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

int main()
{
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (i == j) d[i][j] = 0;
            else d[i][j] = INF;
    while (m--)
    {
        int a, b, c;
        cin >> a >> b >> c;
        d[a][b] = min(d[a][b], c);
    }
    floyd();
    while (k--)
    {
        int l, r;
        cin >> l >> r;
        if (d[l][r] > INF / 2) cout << "impossible" << endl;
        else cout << d[l][r] << endl;
    }
    return 0;
}
相关推荐
虾球xz6 分钟前
游戏引擎学习第41天
学习·算法·游戏引擎
羽墨灵丘42 分钟前
排序算法(4):希尔排序
数据结构·算法·排序算法
小殷要努力刷题!1 小时前
每日一刷——12.10——学习二叉树解题模式(1)
java·学习·算法·leetcode·二叉树·二叉树的建立
gz7seven1 小时前
将分类数据划分为训练集、测试集与验证集
人工智能·算法·分类·数据划分·训练集·验证集·测试集
IT古董1 小时前
【机器学习】机器学习的基本分类-无监督学习-主成分分析(PCA:Principal Component Analysis)
人工智能·学习·算法·机器学习·分类
人需要PID1 小时前
【C语言练习(5)—回文数判断】
c语言·开发语言·学习·算法
小五Z2 小时前
高阶数据结构--B树&&B+树实现原理&&B树模拟实现--Java
java·数据结构·b树·算法
toto4122 小时前
红黑树和B+树
数据结构·b树·算法
chenziang12 小时前
leetcode 100 热题 三数字之和
算法·leetcode·职场和发展
HUT_Tyne2652 小时前
力扣--LCR 131. 砍竹子1
java·算法·leetcode