POJ2387 Til the Cows Come Home(dijkstra + heap 或 SPFA)

Til the Cows Come Home
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 33716 Accepted: 11416

Description

Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wakes her for the morning milking. Bessie needs her beauty sleep, so she wants to get back as quickly as possible. 

Farmer John's field has N (2 <= N <= 1000) landmarks in it, uniquely numbered 1..N. Landmark 1 is the barn; the apple tree grove in which Bessie stands all day is landmark N. Cows travel in the field using T (1 <= T <= 2000) bidirectional cow-trails of various lengths between the landmarks. Bessie is not confident of her navigation ability, so she always stays on a trail from its start to its end once she starts it. 

Given the trails between the landmarks, determine the minimum distance Bessie must walk to get back to the barn. It is guaranteed that some such route exists.

Input

* Line 1: Two integers: T and N 

* Lines 2..T+1: Each line describes a trail as three space-separated integers. The first two integers are the landmarks between which the trail travels. The third integer is the length of the trail, range 1..100.

Output

* Line 1: A single integer, the minimum distance that Bessie must travel to get from landmark N to landmark 1.

Sample Input

5 5
1 2 20
2 3 30
3 4 20
4 5 20
1 5 100

Sample Output

90

Hint

INPUT DETAILS: 

There are five landmarks. 

OUTPUT DETAILS: 

Bessie can get home by following trails 4, 3, 2, and 1.

题目大意:

就是最短路的题.

解题思路:

今天刚好复习了一下dijkstra算法和bellman-ford,也顺便学习了他们各自的优化,以后比赛可以直接上优化版本。dijkstra是单源最短路径的常用算法,他从一个结点出发,然后每次寻找能到达其他没有访问过结点的最短距离,它的核心是松弛操作,然后更新距离.由于dijkstra主要是通过最短距离来更新的,所以我们可以使用优先队列来优化算法。队头的元素总是最小的距离,然后就可以以此更新结点。dijkstra算法比较适用于稠密图,也就是点比较多的图,但是它不能处理负权图,也就是图中存在负边,由于它松弛的特性,所以造就了如果存在负边,将会出现死循环。bellman-ford算法是按边来遍历松弛的,它可以用来判定负环,如果全部遍历完还可以松弛,那么证明存在负权。下面贴一下两种算法各自优化后的代码.

dijkstra + heap优化:

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

const int maxn = 3000;
int d[maxn]; //s到各个点的距离 
int done[maxn];
int p[maxn];
const int INF = 0x3fffff;
int m,n;

struct Edge
{
	int from,to,dist;
	Edge(int u,int v,int d):from(u),to(v),dist(d) {
	}
};

struct HeapNode
{
	int d,u;
	bool operator < (const HeapNode& rhs) const
	{
		return d > rhs.d;
	}
};

vector<Edge> edges; //边的信息 
vector<int> G[maxn]; //存储点的邻接边数 

void init(int n)
{
	for(int i=1;i<=n;i++)
	{
		G[i].clear();
		edges.clear();
	}
}

void AddEdge(int from,int to,int dist)
{
	int m;
	edges.push_back(Edge(from,to,dist));
	m = edges.size();
	G[from].push_back(m-1);
}

void dijkstra_heap(int s)
{
	priority_queue<HeapNode> Q;
	for(int i=1;i<=n;i++) d[i] = INF;
	d[s] = 0;
	memset(done,0,sizeof(done));
	HeapNode c;
	c.d = 0;
	c.u = s;
	Q.push(c);
	while(!Q.empty())
	{
		HeapNode x = Q.top(); Q.pop();
		int u = x.u; //新的结点
		if(done[u]) continue;
		done[u] = true;
		for(int i=0;i<G[u].size();i++)
		{
			Edge& e = edges[G[u][i]];
			if(d[e.to] > d[u] + e.dist)
			{
				d[e.to] = d[u] + e.dist;
				p[e.to]	= G[u][i];
				c.d = d[e.to];
				c.u = e.to;
				Q.push(c); //最小的边权和结点编号 
			}	
		} 
	}
}
int main()
{
	int s,e,dist,i;
	//freopen("1.txt","r",stdin);
	while(cin>>m>>n)
	{
		for(i=1;i<=m;i++)
		{
			cin>>s>>e>>dist;
			AddEdge(s,e,dist);
			AddEdge(e,s,dist);
		}
		dijkstra_heap(1);
		cout<<d[n]<<endl;
	}
} 

SPFA:

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

const int maxn = 3000;
bool inq[maxn];
int cnt[maxn];
int p[maxn]; //最短路中的上一条弧 
int d[maxn]; //s到各个点的距离 
const int INF = 0x3fffff;
int m,n;

struct Edge
{
	int from,to,dist;
	Edge(int u,int v,int d):from(u),to(v),dist(d) {
		
	}
};

vector<Edge> edges;
vector<int> G[maxn];

void init(int n)
{
	for(int i=1;i<=n;i++)
	{
		G[i].clear();
		edges.clear();
	}
}

void AddEdge(int from,int to,int dist)
{
	int m;
	edges.push_back(Edge(from,to,dist));
	m = edges.size();
	G[from].push_back(m-1);
}
              
bool SPFA(int s)
{
	queue<int> Q;
	memset(inq,false,sizeof(inq));
	memset(cnt,0,sizeof(cnt));
	for(int i=1;i<=n;i++) d[i] = INF;
	d[s] = 0; //源点到源点距离为0 
	inq[s] = true; //加入队列 
	Q.push(s);
	
	while(!Q.empty())
	{
		int u = Q.front();
		Q.pop();
		inq[u] = false;
		for(int i=0;i<G[u].size();i++)
		{
			Edge& e = edges[G[u][i]];
			if(d[u] < INF && d[e.to] > d[u] + e.dist)
			{
				d[e.to] = d[u] + e.dist;
				//cout<<d[e.to]<<endl;
				p[e.to] = G[u][i];
				if(!inq[e.to]) {
					Q.push(e.to); inq[e.to] = true;
					if(++cnt[e.to] > n) return false;
				}
			}
		}
	}
	return true;
}

int main()
{
	int s,e,dist,i;
	//freopen("1.txt","r",stdin);
	while(cin>>m>>n)
	{
		for(i=1;i<=m;i++)
		{
			cin>>s>>e>>dist;
			AddEdge(s,e,dist);
			AddEdge(e,s,dist);
		}
		SPFA(1);
		cout<<d[n]<<endl;
	}
} 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值