图论基础算法(C/C++):最短路径:最小生成树,拓扑排序举例

宽度优先遍历求最短路径

在这里插入图片描述

txt文件如下

7 8
1 2
1 4
2 3
4 3
2 6
3 5
4 5
5 7

如图,我们求各节点到节点1的距离,只需在遍历过程增加一个数组存放距离,且在访问节点过程中距离+1即可。注意有向图和无向图皆可。

//无向图宽度优先遍历求最短路径 

#include<iostream>
#include<vector>
#include<queue>
#define MAX 100
using namespace std;

vector <int> G[MAX];
int V;
int E;
int d[MAX];
bool visited[MAX];
void bfs(int v);

int min(int a,int b)
{
	return a<b?a:b;
 } 

//宽度优先搜索 
void BFS()
{
	for(int i = 1;i <= V;i++)
	{
		if(!visited[i])
			bfs(i);
	}
}

void bfs(int v)
{
	queue <int> que;
	que.push(v);
	int count = 0;
	d[v] = 0;
	while(!que.empty())
	{
		int t = que.front();
		visited[t] = true;
		que.pop();
		int len = G[t].size();
		for(int i = 0;i < len;i++)
		{
			if(!visited[G[t][i]])
			{
				que.push(G[t][i]);
				d[G[t][i]] = min(d[G[t][i]],d[t] + 1);
			}
		}
	
	}
}

int main()
{
	cin >> V >>E;
	for(int i = 1;i <= E;i++)
	{
		int s,t;
		cin>>s>>t;
		G[s].push_back(t);
	//	G[t].push_back(s);
	}
	cout <<"邻接表"<<endl; 
	for(int i = 1;i <= V;i++)
	{
		int len = G[i].size();
		cout<<i<<"\t";
		for(int j = 0;j < len;j++)
			cout<<G[i][j]<<" ";
		cout<<endl;
	}
	fill(d,d+V+1,MAX);
	cout<<"BFS遍历,各节点对于节点1的距离"<<endl;
	BFS();

	for(int i = 1;i <= V;i++)
		cout<<d[i]<<" ";
	return 0;
}

在这里插入图片描述

Prim算法求最小生成树

在这里插入图片描述

结果
在这里插入图片描述
最小生成树是 2+3+1+4+2=12

输入txt文件

6
1 2 2 2 3 3
2 2 6 1 4 6
3 2 4 4 5 7
4 1 5 10
5 1 6 2
6 0

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#define MAX 100
#define INF 1e5

using namespace std;
typedef pair<int,int> P;//权值,顶点 
struct edge{int to,cost;};
int V;
int par[MAX];
bool visited[MAX];
vector <edge> G[MAX];

void prim()
{
	cout<<"prim algorithm"<<endl;
	//初始化 
	priority_queue <P,vector<P>,greater<P> > que;//从小到大排列 
	fill(par,par+V+1,-1);
	int s = 1;
	int sum = 0;
	int n = 0;
	que.push(P(0,s));
	while(n++ < V && !que.empty())
	{
		P p = que.top();
		que.pop();
		if(visited[p.second])continue;
		sum += p.first;
		int v = p.second;
		visited[v] = true;
		
		int k = G[v].size();		
		for(int i = 0;i < k;i++)
		{
			edge e;
			e.to = G[v][i].to;
			e.cost = G[v][i].cost;
			if(!visited[e.to])
				que.push(P(e.cost,e.to));
		}
	}	
	
	cout<<"sum="<<sum<<endl;

}



int main()
{
	cin >> V;
	for(int i = 1;i <= V;i++)
	{
		int u,k,v,c;
		cin>>u;
		cin>>k;
		for(int j=0;j<k;j++)
		{
			cin>>v>>c;
			edge e;
			e.to=v;e.cost=c;
			G[u].push_back(e);
			e.to=u;
			G[v].push_back(e);
		}
	}
	
//	for(int i = 1;i <= V;i++)
//	{
//		int k = G[i].size();
//		cout<<i<<" "<<k<<"\t";
//		for(int j=0;j<k;j++)
//		{
//			cout<<G[i][j].to<<" "<<G[i][j].cost<<" ";
//		}
//		cout<<endl;
//	}
	prim();
	cout<<"done"<<endl;
	return 0;
}

Kruskal求最小生成树

图同上
txt文件如下

7 8
1 2 2
1 3 3
2 4 6
2 6 1
3 4 4
3 5 7
4 5 10
5 6 2

//使用kruskal算法,并查集结构求最小生成树 
#include<iostream>
#include<vector>
#include<algorithm>

#define MAX 100
using namespace std;

int par[MAX];
int rank[MAX];
struct edge{int u,v,cost;};

edge es[MAX];
int V,E;

void init(int n)
{
	for(int i=0;i<n;i++)
	{
		par[i] = i;
		rank[i] = 0;
	}
}

int find(int x)
{
	if(par[x] == x)
	{
		return x;
	}
	else
		return par[x] = find(par[x]);
}

void unite(int x,int y)
{
	x = find(x);
	y = find(y);
	if(x == y)
		return;
	if(rank[x] < rank[y])
		par[x] = y;
	else{
		par[y] = x;
		if(rank[x] == rank[y])
			rank[x]++;
	}
}

bool same(int x,int y)
{
	return find(x) == find(y);
}

bool comp(const edge& e1,const edge& e2)
{
	return e1.cost < e2.cost;
}

int kruskal()
{
	sort(es,es+E,comp);
	init(V);
	int res = 0;
	for(int i = 0;i < E;i++)
	{
		edge e;
		e.u = es[i].u;
		e.v = es[i].v;
		e.cost = es[i].cost;	
		if(!same(e.u,e.v))
		{
			unite(e.u,e.v);
			res += e.cost;
			cout<<e.u<<"->"<<e.v<<endl;
		}	
	}
	return res;	
}

int main()
{
	cin>>V>>E;
	for(int i=0;i<E;i++)
	{
		edge e;
		cin>>e.u>>e.v>>e.cost;
		es[i] = e;
	}
	cout<<kruskal()<<endl;
	return 0;
}

选择5条边如下,最小生成树是12
在这里插入图片描述

Dijkstra算法求最短路径

图同prim最小生成树
txt文件同prim算法

//dijkstra算法求最短路径 
#include<iostream>
#include<vector>
#include<queue>
#define MAX 100
#define INF 1e5

using namespace std;

struct edge{int to,cost;};
typedef pair<int,int> P;//first是最短距离,second是顶点编号 
int V;
int d[MAX];
int par[MAX];
vector <edge> G[MAX];
//bool visited[MAX];

void dijkstra()
{
	cout<<"dijkstra algorithm"<<endl;
	//初始化 
	int s = 1;
	priority_queue <P,vector<P>,greater<P> > que;//从小到大排列 
	
	fill(d+1,d+V+1,INF);
//	cout<<d[1]<<endl;
	d[s] = 0;
	par[s] = -1;
	
	que.push(P(0,s));
	while(!que.empty())
	{
		P p = que.top();
		que.pop();
		int v = p.second;
		if(d[v] < p.first)continue;
		for(int i = 0;i < G[v].size();i++)
		{
			edge e = G[v][i];
			if(d[e.to] > d[v] + e.cost)
			{
				d[e.to] = d[v] + e.cost;
				que.push(P(d[e.to],e.to));
				par[e.to] = v;
			}
		 } 
	}
	for(int i = 1;i<=V;i++)
		cout<<d[i]<<" ";
	cout<<endl;
}



int main()
{
	cin >> V;
	for(int i = 1;i <= V;i++)
	{
		int u,k,v,c;
		cin>>u;
		cin>>k;
		for(int j=0;j<k;j++)
		{
			cin>>v>>c;
			edge e;
			e.to=v;e.cost=c;
			G[u].push_back(e);
		}
	}
	
	for(int i = 1;i <= V;i++)
	{
		int k = G[i].size();
		cout<<i<<" "<<k<<"\t";
		for(int j=0;j<k;j++)
		{
			cout<<G[i][j].to<<" "<<G[i][j].cost<<" ";
		}
		cout<<endl;
	}
	dijkstra();
	cout<<"done"<<endl;
	return 0;
}

起点为节点1到各个点的最短距离
分别为0 2 3 7 10 3

在这里插入图片描述

拓扑排序算法

txt文件如下

9 12
1 2
2 5
3 2
3 4
4 2
4 6
5 6
5 7
7 6
7 9
6 8
8 9

在这里插入图片描述

拓扑序之一:1->3->4->2->5->7->6->8->9

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#define MAX_V 100
using namespace std;

vector<int> G[MAX_V];
int in[MAX_V];
int V,E;

void topo()
{
	queue <int>q;
	queue <int>ans;
	for(int i = 1;i <= V;i++)
	{
		if(in[i] == 0)
			q.push(i);
	}
	while(!q.empty()){
		int t = q.front();
		ans.push(t);
		q.pop();
		int len = G[t].size();
		for(int j = 0;j < len;j++)
		{
			in[G[t][j]]--;
			if(in[G[t][j]] == 0)
				q.push(G[t][j]);	

		}	
	}
	int len = ans.size();
	for(int i = 0;i < len;i++)
	{
		cout<<ans.front()<<" ";
		ans.pop();
	}
	cout<<endl;
}

int main()
{
	cin >> V;
	int n;
	cin >> n;
	E = n;
	while(n--)
	{
		int i,j;
		cin >> i;
		cin >> j;
		in[j]++;
		G[i].push_back(j);
	}
	topo();
	
	return 0;
}

总结

图算法有很多应用,至于着色问题,二部图匹配,思路本质上一致,不再赘述。
网络流算法如最大流,指派问题,最小路径覆盖,强连通分量问题等仍在学习中,故不提。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值