1. 程式人生 > 其它 >R語言進行分析,比較詳細的一篇,親測過哦

R語言進行分析,比較詳細的一篇,親測過哦

最短路問題

樸素版Dijkstra(稠密圖)

	s陣列,當前已經確定最短路徑的點
1	dis[1] = 0, dis[i] = 正無窮
2	for(int i = 0; i <= n; i ++)  
		t <- 不在s中距離最近的點
		s <- t 用t更新其他點的距離(從t出去的所有的邊組成的路徑能不能更新其		  他點的距離 
		1 -> t -> x;
		1 ------> x;如果前一種情況的距離小於第二種就可以更新
		dis[x] > dis[t] + w;
									

給定一個 n 個點 m 條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為正值。

請你求出 1 號點到 n 號點的最短距離,如果無法從 1 號點走到 n 號點,則輸出 −1。

輸入格式

第一行包含整數 n 和 m。

接下來 m 行每行包含三個整數 x, y, z,表示存在一條從點 x 到點 y 的有向邊,邊長為 z。

輸出格式

輸出一個整數,表示 1 號點到 n 號點的最短距離。

如果路徑不存在,則輸出 −1。

資料範圍

1 ≤ n ≤ 500,
1 ≤ m ≤ 105,
圖中涉及邊長均不超過10000。

輸入樣例:

3 3
1 2 2
2 3 1
1 3 4

輸出樣例:

3
#include <bits/stdc++.h>

using namespace std;
const int N = 510;

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

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

堆優化版Dijkstra(稀疏圖)

給定一個 n 個點 m 條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為非負值。

請你求出 1 號點到 n 號點的最短距離,如果無法從 1 號點走到 n 號點,則輸出 −1−1。

輸入格式

第一行包含整數 n 和 m。

接下來 mm 行每行包含三個整數 x,y,z表示存在一條從點 x 到點 y 的有向邊,邊長為 z。

輸出格式

輸出一個整數,表示 1號點到 n 號點的最短距離。

如果路徑不存在,則輸出 −1。

資料範圍

1≤n,m≤1.5×105
圖中涉及邊長均不小於 0,且不超過 10000。
資料保證:如果最短路存在,則最短路的長度不超過 109。

輸入樣例:

3 3
1 2 2
2 3 1
1 3 4

輸出樣例:

3
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

typedef pair<int, int> PII;

const int N = 1e6 + 10;

int n, m;
int h[N], w[N], e[N], ne[N], idx;
int dist[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(dist, 0x3f, sizeof dist);
    dist[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, distance = t.first;

        if (st[ver]) continue;
        st[ver] = true;

        for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                heap.push({dist[j], j});
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

int main()
{
    scanf("%d%d", &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;
}

Bellman_Ford(極少數情況,圖中不存在負權迴路(負環))

1.for(int i = 1; i <= n; i ++)
2.備份dist防止串聯
3.for 所有邊 a,b,w
4.dist[b] = min(dist[b], dist[a] + w)(鬆弛操作)
 最後滿足dist[b] <= dist[a] + w(三角不等式)
 
 此演算法不能存在負權迴路
 是否存在負權迴路的驗證方法
 1.迭代K次(不超過k條邊)的最短路的距離
 2.如果第n次迭代時更新了某些邊(說明存在一條最短路徑有n條邊,n+1個點)(說明一定存在負權迴路)
 	一共有n個點,但是出現了n個邊,根據抽屜原理,說明一定有迴路存在

有邊數限制的最短路

給定一個 n 個點 m 條邊的有向圖,圖中可能存在重邊和自環, 邊權可能為負數

請你求出從 1 號點到 n 號點的最多經過 k 條邊的最短距離,如果無法從 1 號點走到 n 號點,輸出 impossible

注意:圖中可能 存在負權迴路

輸入格式

第一行包含三個整數 n,m,k。

接下來 m 行,每行包含三個整數 x,y,z,表示存在一條從點 x 到點 y 的有向邊,邊長為 z。

輸出格式

輸出一個整數,表示從 1 號點到 n 號點的最多經過 k 條邊的最短距離。

如果不存在滿足條件的路徑,則輸出 impossible

資料範圍

1≤n,k≤500,
1≤m≤10000,
任意邊長的絕對值不超過 10000。

輸入樣例:

3 3 1
1 2 1
2 3 1
1 3 3

輸出樣例:

3
#include <bits/stdc++.h>

using namespace std;
const int N = 510, M = 10010;
struct Edge
{
    int a, b, w;
}edges[M];

int dist[N];
int backup[N];
int n, m, k;

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

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

SPFA(常用)

Floyd(多源最短路)