POJ2387,Til the Cows Come Home(Dijkstra算法)

最短路Dijkstra的模板题,不过需要注意的是,这道题的图是无向图。
用了两种方式过这道题,一种是基本的方式,一种是借助优先队列优化的。
第一种代码:(要用邻接矩阵)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define inf 10000005 
using namespace std;
const int maxn=1e3+5;
int map[2*maxn][2*maxn],dis[2*maxn];
bool vis[2*maxn];

void dijkstra(int n)	//用邻接矩阵进行操作的dijkstra,时间复杂度为O(n^2),其原理与最小生成树Prim算法很相似 
{
	for(int i=1;i<=n;i++)	//初始化,起点设为1 
	{
		dis[i]=map[1][i];
		vis[i]=0;
	}
	vis[1]=1;	//vis[i]=1表示顶点i已经更新过了 
	for(int i=1;i<=n;i++)
	{
		int temp=inf,k=0;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&dis[j]<temp)
				temp=dis[k=j];
		if(temp==inf)	break;
		vis[k]=1;
		for(int j=1;j<=n;j++)	//dijkstra与Prim不同的地方就在这里,更新的方式不同罢了 
			dis[j]=min(dis[j],dis[k]+map[k][j]);	//源点1到j的最小距离是无通过k点和通过k点两者之间的最小值 
	}
}

int main()
{
	int n,T;
	scanf("%d%d",&T,&n);	//注意输入的顺序
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(i!=j)	map[i][j]=inf;
			else map[i][j]=0;
	for(int i=1;i<=T;i++)
	{
		int u,v,cost;
		scanf("%d%d%d",&u,&v,&cost);
		map[u][v]=map[v][u]=min(map[u][v],cost);	//注意,是两者之间的最小值
	}
	dijkstra(n);
	printf("%d\n",dis[n]);
	return 0;
}

第二种方式:(用邻接矩阵)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define inf 10000005 
using namespace std;
const int maxn=1e3+5;
struct road		 
{
	int cost,v;
	bool operator < (const road& a) const	//重置运算符“<”,使优先队列能够按cost从小到大排序 
	{
		return cost>a.cost;
	 } 
};
vector<road> G[maxn];	//建立邻接链表 
int dis[maxn];	//dis记录从顶点1开始到其他所有顶点的最短路径 
bool vis[maxn];	//vis标志顶点i是否被更新过

void dijkstra(int n)	//用优先队列优化的dijkstra,时间复杂度为O(ElogE) 
{
	priority_queue<road> Q;	
	for(int i=1;i<=n;i++)	//初始化 
	{
		dis[i]=inf;
		vis[i]=0; 
	}
	dis[1]=0;
	road u;
	u.v=1; u.cost=0;
	Q.push((u)); 
	//Q.push( (road){0,1} );	//采用这种方法插入会使代码更加好看,可惜提交的时候CE了,就没采用
	while(!Q.empty())
	{
		road top=Q.top(); Q.pop();	//取出队列队首,即边权最短的元素,并将其弹出队列 
		int v=top.v;	//取其终点 
		if(vis[v])	continue;	//如果这个顶点已经被更新过,则继续下次循环,否则更新以它为起点的边 
		vis[v]=1;	 
		for(int i=0;i<G[v].size();i++)
		{
			road r=G[v][i];	//取出边 
			if(dis[r.v]>dis[v]+r.cost)	//如果原本从1到终点r.v的值dis[r.v]大于从1到v再到终点r.v的值,则更新dis[r.v]以及队列 
			{
				dis[r.v]=dis[v]+r.cost;
				road k;
				k.v=r.v; k.cost=dis[r.v];
				Q.push(k);
				//Q.push( (road){dis[r.v],r.v} );
			}
		 } 
	}
}

int main()
{
	int n,T;
	scanf("%d%d",&T,&n);
	for(int i=1;i<=T;i++)
	{
		int u; road a;
		scanf("%d%d%d",&u,&a.v,&a.cost);
		G[u].push_back(a);
		swap(a.v,u);	
		G[u].push_back(a);	//记得这是个无向图
	}
	dijkstra(n);
	printf("%d\n",dis[n]);
	return 0;
}

好几次提交的时候RE了。。。因为输入的顺序是T,N,而不是N,T,一开始反了过来就错了。。。要注意

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值