圖的整理與總結
阿新 • • 發佈:2018-12-07
1.dijkstra演算法
①求從source到destination的最短路徑(最短距離、最短路徑條數、最短路徑上的節點數以及路徑)
②若最短路徑不唯一,則再求從source到destination的最小代價
③若最短路徑還是不唯一,則再求從source到destination的最大節點權值和
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <cctype> #include <climits> #include <iostream> #include <algorithm> #include <string> #include <vector> #include <queue> #include <stack> #include <map> #include <set> using namespace std; #define INF 0x3f3f3f3f #define MAXN 500 int d[MAXN][MAXN]; //d[i][j]-從i到j的距離 (由題目給出) int c[MAXN][MAXN]; //c[i][j]-從i到j的代價 (由題目給出) int w[MAXN]; //w[i]-i的權值(由題目給出) int dis[MAXN]; //dis[i]-從起點到i的最短距離 int cost[MAXN]; //cost[i]-從起點到i的最小代價 int maxw[MAXN]; //maxw[i]-從起點到i的最大權值 int cnt[MAXN]; //cnt[i]-從起點到i的最短路徑條數 int num[MAXN]; //num[i]-從起點到i的最短路徑上的節點個數 int pre[MAXN]; //pre[i]-最短路徑上i的前一個節點 int vis[MAXN]; //vis[i]-i是否被訪問過 void dijkstra(int source, int destination, int n) //source-起點 destination-終點 n-節點數 { for (int i = 0; i < n; i++) { dis[i] = INF; cost[i] = INF; maxw[i] = 0; cnt[i] = 0; num[i] = 0; pre[i] = -1; vis[i] = 0; } dis[source] = 0; cost[source] = 0; maxw[source] = w[source]; cnt[source] = 1; num[source] = 1; for (int i = 0; i < n; i++) { int min = INF, k = -1; for (int j = 0; j < n; j++) { if (!vis[j] && dis[j] < min) { min = dis[j]; k = j; } } if (k == -1) //沒有符合條件的節點則返回 return; vis[k] = 1; if (k == destination) //終點已求得最短路徑則返回 return; for (int j = 0; j < n; j++) { if (!vis[j] && d[k][j] != INF) { if (dis[k] + d[k][j] < dis[j]) //從起點經過k到j的距離比從起點到j的距離短 { dis[j] = dis[k] + d[k][j]; cost[j] = cost[k] + c[k][j]; maxw[j] = maxw[k] + w[j]; cnt[j] = cnt[k]; num[j] = num[k] + 1; pre[j] = k; } else if (dis[k] + d[k][j] == dis[j]) { cnt[j] += cnt[k]; if (cost[k] + c[k][j] < cost[j]) //在距離相同的情況下,從起點經過k到j的代價比從起點到j的代價小 { cost[j] = cost[k] + c[k][j]; maxw[j] = maxw[k] + w[j]; num[j] = num[k] + 1; pre[j] = k; } else if (cost[k] + c[k][j] == cost[j] && maxw[k] + w[j] > maxw[j]) //在距離和代價相同的情況下,從起點經過k到j的節點權值比從起點到j的節點權值大 { maxw[j] = maxw[k] + w[j]; num[j] = num[k] + 1; pre[j] = k; } } } } } } void print_path(int source, int x) //遞迴輸出最短路徑(不包括起點,因為輸出第一個節點的時候不需要"->") { if (x == source) return; print_path(source, pre[x]); cout << "->" << x; } int main() { int n, m; cin >> n >> m; //n-節點數 m-邊數 for (int i = 0; i < n; i++) { int v, ww; cin >> v >> ww; //v-節點號 ww-權值 w[v] = ww; } memset(d, INF, sizeof(d)); memset(c, INF, sizeof(c)); for (int i = 0; i < m; i++) { int v, u, dd, cc; cin >> v >> u >> dd >> cc; //v-邊的起點 u-邊的終點 dd-邊的距離 cc-邊的代價 d[v][u] = d[u][v] = dd; c[v][u] = c[u][v] = cc; } int source, destination; cin >> source >> destination; dijkstra(source, destination, n); cout << dis[destination] << " " << cost[destination] << " " << maxw[destination] << " " << cnt[destination] << " " << num[destination] << endl; cout << source; print_path(source, destination); return 0; }
2.並查集
一般用於:
①求該圖的連通分支
②判斷該圖是否有環
③Kruskal演算法
#define MAXN 1000 int f[MAXN]; void Init() //初始化每個節點的祖先都是自己 { for (int i = 1; i <= n; i++) f[i] = i; } int Find(int x) //查詢節點x的祖先 { if (x != f[x]) f[x] = Find(f[x]); //回溯時壓縮路徑,讓每一個節點直接和其祖先連線 return f[x]; } void Union(int x, int y) //合併兩個分支 { int a = Find(x); int b = Find(y); if (a != b) f[a] = b; }