图的整理与总结

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;

}

猜你喜欢

转载自blog.csdn.net/ryo_218/article/details/82503405
今日推荐