1. 程式人生 > >圖論 模板(1)

圖論 模板(1)

最短路(ShortextPath)

Dijkstra

#include<bits/stdc++.h>
using namespace std; 
/*Dijkstra演算法*/
int a[3010][3010],d[3010],n,m;
bool v[3010];
void dijkstra()
{
	memset(d,0x3f,sizeof(d));//dist陣列 
	memset(v,0,sizeof(v));//節點標記 
	d[1]=0;
	for (int i=1;i<n;i++)
	{//重複進行n-1次 
		int x=0;
		//找到未標記節點中dist最小的 
		for (
int j=1;j<=n;j++) if (!v[j]&&(x==0||d[j]<d[x])) x=j; v[x]=1; //用全域性最小值點X更新其他節點 for (int y=1;y<=n;y++) d[y]=min(d[y],d[x]+a[x][y]); } } int main() { cin>>n>>m; //構建鄰接矩陣 memset(a,0x3f,sizeof(a)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { int
x,y,z; scanf("%d%d%d",&x,&y,&z); a[x][y]=min(a[x][y],z); } //求單源最短路徑 dijkstra(); for (int i=1;i<=n;i++) printf("%d\n",d[i]); }

有向圖的Dijkstra演算法實現(可輸出具體最短路徑)

轉自http://www.wutianqi.com/?p=1890

/***************************************
* About:    有向圖的Dijkstra演算法實現
* Author:   Tanky Woo
* Blog:     www.WuTianQi.com
***************************************/
#include <iostream> using namespace std; const int maxnum = 100; const int maxint = 999999; // 各陣列都從下標1開始 int dist[maxnum]; // 表示當前點到源點的最短路徑長度 int prev[maxnum]; // 記錄當前點的前一個結點 int c[maxnum][maxnum]; // 記錄圖的兩點間路徑長度 int n, line; // 圖的結點數和路徑數 // n -- n nodes // v -- the source node // dist[] -- the distance from the ith node to the source node // prev[] -- the previous node of the ith node // c[][] -- every two nodes' distance void Dijkstra(int n, int v, int *dist, int *prev, int c[maxnum][maxnum]) { bool s[maxnum]; // 判斷是否已存入該點到S集合中 for(int i=1; i<=n; ++i) { dist[i] = c[v][i]; s[i] = 0; // 初始都未用過該點 if(dist[i] == maxint) prev[i] = 0; else prev[i] = v; } dist[v] = 0; s[v] = 1; // 依次將未放入S集合的結點中,取dist[]最小值的結點,放入結合S中。 // 一旦S包含了所有V中頂點,dist就記錄了從源點到所有其他頂點之間的 //最短路徑長度。 // 注意是從第二個節點開始,第一個為源點。 for(int i=2; i<=n; ++i) { int tmp = maxint; int u = v; // 找出當前未使用的點j的dist[j]最小值。 for(int j=1; j<=n; ++j) if((!s[j]) && dist[j]<tmp) { u = j; // u儲存當前鄰接點中距離最小的點的號碼。 tmp = dist[j]; } s[u] = 1; // 表示u點已存入S集合中。 //三角形更新,更新dist。 for(int j=1; j<=n; ++j) if((!s[j]) && c[u][j]<maxint) { int newdist = dist[u] + c[u][j]; if(newdist < dist[j]) { dist[j] = newdist; prev[j] = u; } } } } // 查詢從源點v到終點u的路徑,並輸出。 void searchPath(int *prev,int v, int u) { int que[maxnum]; int tot = 1; que[tot] = u; tot++; int tmp = prev[u]; while(tmp != v) { que[tot] = tmp; tot++; tmp = prev[tmp]; } que[tot] = v; for(int i=tot; i>=1; --i) if(i != 1) cout << que[i] << " -> "; else cout << que[i] << endl; } int main() { //freopen("input.txt", "r", stdin); // 各陣列都從下標1開始 // 輸入結點數 cin >> n; // 輸入路徑數 cin >> line; int p, q, len; // 輸入p, q兩點及其路徑長度 // 初始化c[][]為maxint for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j) c[i][j] = maxint; for(int i=1; i<=line; ++i) { cin >> p >> q >> len; if(len < c[p][q]) // 有重邊 { c[p][q] = len; // p指向q c[q][p] = len; // q指向p,這樣表示無向圖 } } for(int i=1; i<=n; ++i) dist[i] = maxint; for(int i=1; i<=n; ++i) { for(int j=1; j<=n; ++j) printf("%8d", c[i][j]); printf("\n"); } Dijkstra(n, 1, dist, prev, c); // 最短路徑長度 cout << "源點到最後一個頂點的最短路徑長度: " << dist[n] << endl; // 路徑 cout << "源點到最後一個頂點的路徑為: "; searchPath(prev, 1, n); }

Dijkstra with priority-queue

#include<bits/stdc++.h>
using namespace std; 
/*堆優化*/
const int N=100010,M=1000010;
int head[N],ver[N],edge[N],Next[N],d[N];//頂點 vertex 邊 edge 距離 distance
bool v[N];
int n,m,tot;
//大根堆(優先佇列),pair的第二維為節點編號
//pair的第一維為dist的相反數(利用相反數變成小根堆) 
priority_queue<pair<int,int> >q;

void add(int x,int y,int z)
{
	ver[++tot]=y,edge[tot]=z,Next[tot]=head[tot],head[x]=tot;
}
void dijkstra()
{
	memset(d,0x3f,sizeof(d));//dist陣列
	memset(v,0,sizeof(v));//節點標記
	d[1]=0;
	q.push(make_pair(0,1));
	while (q.size())
	{//取出堆頂 
		int x=q.top().second;
		q.pop();
		if (v[x]) continue;
		v[x]=1;
		//掃描所有出邊 
		for (int i=head[x];i;i=Next[i])
		{
			int y=ver[i],z=edge[i];
			if (d[y]>d[x]+z)
			{//更新,把新的二元組插入堆 
				d[y]=d[x]+z;
				q.push(make_pair(-d[y],y));
			}
		}
	}
}
int main()
{
	cin>>n>>m;
	//構建鄰接表 
	for (int i=1;i<=m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
	}
	//求單源最短路徑 
	dijkstra();
	for (int i=1;i<=n;i++)
		printf("%d\n",d[i]);
}

SPFA

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
const int M=1000010;
int head[N],ver[M],edge[M],Next[M],d[N];
int n,m,tot;
queue<int>q;
bool v[N];
void add(int x,int y,int z)
{
	ver[++tot]=y;
	edge[tot]=z;
	Next[tot]=head[x];
	head[x]=tot;
}
void spfa()
{
	memset(d,0x3f,sizeof(d));//dist陣列 
	memset(v,0,sizeof(v));//是否在佇列中 
	d[1]=0,v[1]=1;
	q.push(1);
	while(q.size())
	{//取出隊頭 
		int x=q.front();
		q.pop();
		v[x]=0;
		//掃描所有出邊 
		for(int i=head[x];i;i=Next[i])
		{
			int y=ver[i],z=edge[i];
			if(d[y]>d[x]+z)
			{//更新,把新的二元組插入堆 
				d[y]=d[x]+z;
				if(!v[y]) q.push(y) , v[y]=1;
			}
		}
	}
}
int main()
{
	cin>>n>>m;
	//構建鄰接表 
	for (int i=1;i<=m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
	}
	//求單源最短路徑 
	spfa();
	for (int i=1;i<=n;i++)
		printf("%d\n",d[i]);
}

Bellman-Ford

#include<iostream>
using namespace std;
const int maxnum=100;
const int maxint=99999;
//邊 
typedef struct edge
{
	int u,v;//源點,終點 
	int weight;//邊的權值 
}Edge;

Edge edge[maxnum];//儲存邊的權值 
int dist[maxnum];//結點到源點的最小距離
int nodenum,edgenum,source;//結點數,邊數,源點
//初始化圖 
void init()
{
	//輸入結點數,邊數,源點 
	cin>>nodenum>>edgenum>>source;
	for (int i=1;i<=nodenum;i++)
		dist[i]=maxint;
	dist[source]=0;
	for (int i=1;i<=edgenum;i++)
	{
		cin>>edge[i].u>>edge[i].v>>edge[i].weight;
		if (edge[i].u==source)//注意這裡的設定初始情況 
			dist[edge[i].v]=edge[i].weight;
	}
}

//鬆弛計算 
void relax (int u,int v,int weight)
{
	if (dist[u]+weight<dist[v])
		dist[v]=dist[u]+weight;
}
bool Bellman_Ford()
{
	for (int i=1;i<nodenum;i++)
		for (int j=1;j<=edgenum;j++)
			relax (edge[j].u,edge[j].v,edge[j].weight);
	bool flag=1;
	//判斷是否有負環路 
	for (int i=1;i<=edgenum;i++)
		if (dist[edge[i].u]+edge[i].weight<dist[edge[i].v])
		{
			flag=0;
			break;
		}
	return flag;
} 
int main()
{
	init();
	if (Bellman_Ford())
		for (int i=1;i<=nodenum;i++)
			cout<<dist[i]<<endl;
	return 0;
}

Floyed

/*
*Floyed演算法