最短路的几种常用算法

hdu1874 畅通工程续

陈年水题,老少皆宜,最短路的入门作业

但是换个刷法,会更有意思

最短路的 Floyd 算法:

#include<stdio.h>
#include<string.h>
#define find_min(a,b) a<b?a:b
#define MAX 0xfffffff
int n,m,map[201][201],dist[201],vis[201];
void getmap()
{
	int i,j,a,b,c;
	for(i=0;i<n;i++){
		for(j=0;j<n;j++)
			map[i][j]=(i==j?0:MAX);
	}
	for(i=0;i<m;i++){
		scanf("%d%d%d",&a,&b,&c);
		map[a][b]=map[b][a]=find_min(map[a][b],c);
	}
}
void floyd(int sp,int ep){
	for(int k=0;k<n;k++)
	{
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				map[i][j]=find_min(map[i][j],map[i][k]+map[k][j]);
	}
	printf("%d\n",map[sp][ep]<MAX?map[sp][ep]:-1);
}
int main()
{
	int s,e;
	while(~scanf("%d%d",&n,&m))
	{
		getmap();
		scanf("%d%d",&s,&e);
		floyd(s,e);
	}
	return 0;
}

最短路dijkstra算法的 邻接阵实现:

#include<stdio.h>
#include<string.h>
#define find_min(a,b) a<b?a:b
const int MAX = 0xfffffff;
const int N = 210;
int n,m,map[N][N],dist[N],vis[N];
void getmap()
{
	int i,j,a,b,c;
	memset(vis,0,sizeof(vis));
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
			map[i][j] = (i==j?0:MAX);
	}
	for(i=0;i<m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		map[a][b]=map[b][a]=find_min(map[a][b],c);
	}
}
void dij(int start,int to)
{
	int i,cur,next;
	for(i=0;i<n;dist[i++]=MAX);
	dist[start]=0;
	cur=start;
	while(1){
		vis[cur]=1;
		int min=MAX;
		for(i=0;i<n;i++){
			if(vis[i])continue;
			if(dist[i]-map[i][cur]>dist[cur])
				dist[i]=map[i][cur]+dist[cur];
			if(dist[i]<min){
				min=dist[i]; next=i;
			}
		}
		cur=next;
		if(cur==to)break;
		if(min==MAX)break;
	}
	printf("%d\n",dist[to]<MAX?dist[to]:-1);
}
int main()
{
	int sp,ep;
	while(~scanf("%d%d",&n,&m))
	{
		getmap();
		scanf("%d%d",&sp,&ep);
		dij(sp,ep);
	}
	return 0;
}

最短路dijkstra算法 的邻接表实现:

#include<stdio.h>
#include<string.h>
const int MAX = 0xfffffff;
const int N =210;

struct Edge
{
	int s,e,v;
	int next;
}edge[1001];

int n,m,e_num,head[N],dist[N],vis[N];

void AddEdge(int a,int b,int c)
{
	edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c;
	edge[e_num].next=head[a]; head[a]=e_num++;
	
	edge[e_num].s=b; edge[e_num].e=a; edge[e_num].v=c;
	edge[e_num].next=head[b]; head[b]=e_num++;
}

void getmap()
{
	int i,a,b,c;
	e_num=0;
	memset(head,-1,sizeof(head));
	memset(vis,0,sizeof(vis));
	for(i=0;i<n;dist[i++]=MAX);
	for(i=0;i<m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		AddEdge(a,b,c);
	}
}
void dij(int sp,int ep)
{
	int i,cur,next;
	dist[sp]=0;
	vis[sp]=1;
	
	cur=sp;
	while(1)
	{
		if(cur==ep)break;
		vis[cur]=1;
		for(i=head[cur];i!=-1;i=edge[i].next)//更新和cur相邻点的dist[]
		{
			int u=edge[i].e;
			if(vis[u])continue;
			if(dist[u] - edge[i].v > dist[cur])
				dist[u]=edge[i].v+dist[cur];
		}
		int min=MAX;
		for(i=0;i<n;i++)//找到最近的点,作为下一个cur值
		{
			if(vis[i])continue;
			if( dist[i] < min){
				min=dist[i]; next=i;
			}
		}
		cur=next;
		if(min==MAX)break;
	}
	printf("%d\n",dist[ep]<MAX?dist[ep]:-1);
}
int main()
{
	int sp,ep;
	while(~scanf("%d%d",&n,&m))
	{
		getmap();
		scanf("%d%d",&sp,&ep);
		dij(sp,ep);
	}
	return 0;
}

最短路spfa算法 :

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAX = 0xffffff;
const int N = 201;
struct Edge
{
	int s,e,v;
	int next;
}edge[1001];

int n,m,e_num,vis[N],head[N],dist[N];

void AddEdge(int a,int b,int c)
{
	edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c;
	edge[e_num].next=head[a]; head[a]=e_num++;

	edge[e_num].s=b; edge[e_num].e=a; edge[e_num].v=c;
	edge[e_num].next=head[b]; head[b]=e_num++;
}

void getmap()
{
	int i,a,b,c;
	e_num=0;
	memset(vis,0,sizeof(vis));
	memset(head,-1,sizeof(head));
	for(i=0;i<n;dist[i++]=MAX);
	for(i=0;i<m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		AddEdge(a,b,c);
	}
}

void spfa(int sp,int ep)
{
	queue <int> q;

	q.push(sp);
	vis[sp]=1;
	dist[sp]=0;

	while(!q.empty()){
		int cur=q.front();
		q.pop();
		vis[cur]=0;
		for(int i=head[cur];i!=-1;i=edge[i].next){
			int u=edge[i].e;
			if(dist[u]>dist[cur]+edge[i].v){
				dist[u]=dist[cur]+edge[i].v;
				if(!vis[u]){
					q.push(u);vis[u]=1;
				}
			}
		}
	}
	printf("%d\n",dist[ep]<MAX?dist[ep]:-1);
}

int main()
{
	int sp,ep;
	while(~scanf("%d%d",&n,&m))
	{
		getmap();
		scanf("%d%d",&sp,&ep);
		spfa(sp,ep);
	}
	return 0;
}

dij + 优先队列 优化:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;

const int N = 1001;
const int MAX = 0xfffffff;

struct Node
{
	int id,val;
	bool operator < (const Node &a) const
	{
		return a.val < val;
	}
};

struct Edge
{
	int s,e,v;
	int next;
}edge[4*N];

int n,m,e_num,vis[N],dist[N],head[N];

void AddEdge(int a,int b,int c)
{
	edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c;
	edge[e_num].next=head[a]; head[a]=e_num++;

	edge[e_num].s=b; edge[e_num].e=a; edge[e_num].v=c;
	edge[e_num].next=head[b]; head[b]=e_num++;
}

void getmap()
{
	int i,a,b,c;
	e_num=0;
	memset(head,-1,sizeof(head));
	memset(vis,0,sizeof(vis));
	for(i=0;i<n;dist[i++]=MAX);
	for(i=0;i<m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		AddEdge(a,b,c);
	}
}

void dij(int sp,int ep)
{
	Node cur,next;
	priority_queue <Node> q;

	dist[sp]=0;
	cur.id=sp; cur.val=0;
	q.push(cur);

	while(!q.empty()){
		cur=q.top();//出队是选择val最小的点出队,不需要再次查找
		q.pop();
		if(cur.id==ep)break;

		if(vis[cur.id])continue;

		vis[cur.id]=1;
		for(int i=head[cur.id];i!=-1;i=edge[i].next)
		{
			int u=edge[i].e;
			if(vis[u])continue;
			if(dist[u] - cur.val > edge[i].v){
				dist[u]=cur.val + edge[i].v;
				next.id=u;
				next.val=dist[u];
				q.push(next);
			}
		}
	}
	
	printf("%d\n",dist[ep]<MAX?dist[ep]:-1);
}

int main()
{
	int sp,ep;
	while(~scanf("%d%d",&n,&m))
	{
		getmap();
		scanf("%d%d",&sp,&ep);
		dij(sp,ep);
	}
	return 0;
}

刷水其实很有意思,真的是,真的是这样……

你可能感兴趣的:(c,算法,优化,struct,ini,作业)