首页 > 其他分享 >有向图最小环的三种普遍求法 Dijkstra

有向图最小环的三种普遍求法 Dijkstra

时间:2022-12-19 13:44:35浏览次数:35  
标签:有向图 dist int 求法 Dijkstra heap push include

有向图的最小环问题

Dijkstra两点距离和

跑 \(n\) 遍 \(\text{Dijkstra}\) 求出任意两点间距离,然后枚举任意两点\(i, j\),可以发现 \(dist[i][j] + dist[j][i]\) 就是一个可能的最小环的长度。

由于这是有向图,所以从 \(i\) 走到 \(j\) 再从 \(j\) 走到 \(i\) 便构成了一个环。

时间复杂度 \(O(nm\log n)\)

#include <algorithm>
#include <cstring>
#include <iostream>
#define INF 0x3f3f3f3f
using namespace std;

const int N = 1e3 + 10;

vector<PII> g[N];

int dist[N][N];
bool st[N];
int n, m;
void dijkstra(int s)
{
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, s});
    for (int i = 1; i <= n; i++)
        dist[s][i] = INF, st[i] = 0;
    dist[s][s] = 0;
    while (heap.size())
    {
        auto t = heap.top().y;
        heap.pop();
        if (st[t])
            continue;
        st[t] = 1;
        for (auto j : g[t])
        {
            if (dist[s][j.x] > dist[s][t] + j.y)
            {
                dist[s][j.x] = dist[s][t] + j.y;
                heap.push({dist[s][j.x], j.x});
            }
        }
    }
}

int mn = INF;

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a].push_back({b, c});
    }
    for (int i = 1; i <= n; i++)
        dijkstra(i);

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (i != j)
                mn = min(mn, dist[i][j] + dist[j][i]);

    cout << mn << endl;
    return 0;
}

Dijkstra回到起点方法

已每个点为起点跑 \(\text{Dijkstra}\),如果在从 \(t\) 扩展 \(j\) 的时候回到了起点,那么就代表产生了一个环,此时更新答案为 \(\min\{ans, dist[t] + w_{t\rightarrow j}\}\),表示从起点走到 \(t\) 再走过这一条连边的距离和。

#include <algorithm>
#include <cstring>
#include <iostream>
#define INF 0x3f3f3f3f
using namespace std;

const int N = 1e3 + 10;

vector<PII> g[N];

int dist[N];
bool st[N];
int n, m;
int mn = INF;
void dijkstra(int s)
{
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, s});
    for (int i = 1; i <= n; i++)
        dist[i] = INF, st[i] = 0;
    dist[s] = 0;
    while (heap.size())
    {
        auto t = heap.top().y;
        heap.pop();
        if (st[t])
            continue;
        st[t] = 1;
        for (auto j : g[t])
        {
            if (j.x == s)
                mn = min(mn, dist[t] + j.y);
            if (dist[j.x] > dist[t] + j.y)
                dist[j.x] = dist[t] + j.y, heap.push({dist[j.x], j.x});
        }
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a].push_back({b, c});
    }
    for (int i = 1; i <= n; i++)
        dijkstra(i);

    cout << mn << endl;
    return 0;
}

Dijkstra删边方法

删掉一条 \(u\rightarrow v\) 的边,之后以这条边任意一个端点为起点跑一遍 \(\text{Dijkstra}\),这样 \(dist[u/v] + w\) 即为一个经过 \(u, v\) 的最小环的长度,迭代 \(m\) 次取最小值即可。

时间复杂度 \(O(m^2\log n)\)。

实现起来可以选择被到达的点 \(v\) 作为起点跑一遍最短路,这样省去了删边的步骤(\(v\) 不能走 \(u\rightarrow v\))。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iostream>
#include <queue>
#include <stack>
#define x first
#define y second
#define INF 0x3f3f3f3f
#define speedup (ios::sync_with_stdio(0), cin.tie(0), cout.tie(0))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int N = 1e5 + 10;

struct qwq
{
    int u, v, w;
} edge[N];

vector<PII> g[N];

int dist[N];
bool st[N];
int mn = INF;

void dijkstra(int s)
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, s});
    dist[s] = 0;
    while (heap.size())
    {
        auto t = heap.top().y;
        heap.pop();
        if (st[t])
            continue;
        st[t] = 1;
        for (auto j : g[t])
        {
            if (dist[j.x] > dist[t] + j.y)
            {
                dist[j.x] = dist[t] + j.y;
                heap.push({dist[j.x], j.x});
            }
        }
    }
}

int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a].push_back({b, c});
        edge[i] = {a, b, c};
    }
    for (int i = 1; i <= m; i++)
    {
        dijkstra(edge[i].v);
        mn = min(mn, dist[edge[i].u] + edge[i].w);
    }
    cout << mn << endl;
    return 0;
}

另外这个方法记录最小环方案也很方便,同样也适用于无向图最小环问题。

标签:有向图,dist,int,求法,Dijkstra,heap,push,include
From: https://www.cnblogs.com/MoyouSayuki/p/16991939.html

相关文章

  • dijkstra最短路代码模板更新
     fromcollectionsimportdefaultdictfromheapqimportheappush,heappopdefdijkstra(edges,start_node,end_node):graph=defaultdict(dict)f......
  • Dijkstra 算法说明与实现
    Dijkstra算法说明与实现作者:Grey原文地址:博客园:Dijkstra算法说明与实现CSDN:Dijkstra算法说明与实现问题描述问题:给定出发点,出发点到所有点的距离之和最小是多少?......
  • 经典算法——最短路径(Floyd+Dijkstra)
    Floyd时间复杂度:O(n^3)简介:作为最短路算法中复杂度最高的算法没有之一,标志性结构三层循环,核心结构本质DP思想具 有动态规划的无后效性他真的没有优点啦?!不,他有!虽然SPF......
  • 最短路径Dijkstra算法
    最短路径最短路径的性质:路径是有向的权重不一定等价于距离,权重也可以指时间,花费或者其他并不是所有顶点都是可达的负权重会使得问题更复杂(Dijkstra算法不适用于......
  • 细分图中的可到达节点 Dijkstra算法Python实现
    题目大意个无向图(原始图)中有n个节点,编号从0到n-1。对每条边增加若干节点构建“细分图”,求解从节点0出发能抵达的不超过距离为maxMove的节点数量。输入:edges=[......
  • 882. 细分图中的可到达节点 ----- Dijkstra算法、图
    给你一个无向图(原始图),图中有n个节点,编号从0到n-1。你决定将图中的每条边细分为一条节点链,每条边之间的新节点数各不相同。图用由边组成的二维数组edges表示,其......
  • Dijkstra算法求带权图的单源最短路径
    Dijkstra算法:给出一个带权无向图,要求指定顶点到图中每一个点的最短路径。首先我们定义一个邻接矩阵c,c[i][j]用来表示从顶点i到顶点j的权重,用一个一维数组prev[]来记录指定......
  • pat dijkstra系列题目代码详解
    1003:1#include<bits/stdc++.h>2usingnamespacestd;3#defineintlonglong4#defineIOSios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);5const......
  • 存题(图的相关判断和两道精品dijkstra)
    图的判断:https://pintia.cn/problem-sets/994805342720868352/exam/problems/994805351814119424https://pintia.cn/problem-sets/994805342720868352/exam/problems/994......
  • Dijkstra Algorithm
    与BFS不同的是每条路径多了权重1.步骤:找到最便宜的节点,即可在最短时间内前往的节点对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新其开销。重复这个过程,直到对......