1. 程式人生 > >POJ 2387-Til the Cows Come Home(最短路問題)

POJ 2387-Til the Cows Come Home(最短路問題)

POJ 2387-Til the Cows Come Home

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.

典型的最短路問題

  • Floyd-Warshall演算法 Floyd-Warshall演算法是解決任意兩點間的最短路徑的一種演算法,可以正確處理有向圖或負權的最短路徑問題 同時也被用於計算有向圖的傳遞閉包。 Floyd-Warshall演算法的時間複雜度為O(N3),空間複雜度為O(N2)。 原理很簡單,用一個二維陣列來存圖,然後每次判斷兩個點之間是否能通過第三個點來使路徑變短 a–b 看是否有一個點 k 可以 a–k--b使路徑變短,變短了就更新這個值 假如這個k==1
for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		if(mp[i][j]>mp[i][1]+mp[1][j])
			mp[i][j]=mp[i][1]+mp[1][j]

同理如果k==2

for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		if(mp[i][j]>mp[i][2]+mp[2][j])
			mp[i][j]=mp[i][2]+mp[2][j];

所以我們想看a-b 的最短路只要比較通過1-n所有點中轉後的最小的一個就是a-b的最短路,依次更新任意兩點之間的最短路,程式碼如下:(當然這樣的複雜度時n^3,肯定會超時,我們在這只是介紹下這種最簡單的最短路)

#include <iostream>
#include <cstdio>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;
int mp[1010][1020];
void init()
{
	memset(mp,inf,sizeof(mp));
}
int main()
{
	int t,n;
	scanf("%d%d",&t,&n);
	init();
	int a,b,w;
	for(int i=0;i<t;i++)
	{
		//cin>>a>>b>>w;
		scanf("%d%d%d",&a,&b,&w);
		mp[a][b]=w;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			for(int k=1;k<=n;k++)
			{
				if(mp[i][j]>mp[i][k]+mp[k][j])
					mp[i][j]=mp[i][k]+mp[k][j];
			}
		}
	}
	cout<<mp[1][n]<<endl;
	
	return 0;
}
  • Dijkstra演算法 Dijkstra演算法是典型的用來解決單源最短路徑的演算法,用來求從起始點到其他所有點最短路徑,時間複雜度是o(n^3)。 該演算法採用了貪心的思想,每次都查詢與該點距離最近的點 ,也因為這樣,它不能用來解決存在負權邊的圖。 解決的問題大多是這樣的:有一個無向圖G(V,E),邊E[i]的權值為W[i],找出V[0]到V[i]的最短路徑。 原理就是每次找到離出發點最近的點,然後用這個出發點到這個點所在的邊來鬆弛其他的邊,當然已經確定是最短的邊在鬆弛的時候要跳過去。
步驟:1.先將所有的頂點分成兩個集合,P和Q,P是已知最短路的集合,Q 是未知最短路的集合,用一個vis[]陣列來區分P和Q ,vis[i]==1就是P 反之就在Q裡. 2.用dis陣列記錄從初始點s到i的最短路,每次從P中找一個最小的點,用這個點來鬆弛其他的所有點,更新dis陣列。

程式碼如下:

///這是用一個mp陣列來記錄的路徑 空間複雜度是o(n^2)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;
int mp[1020][1020];
int dis[1010];//儲存的是從目的地到各個點的最短路 
int vis[1010];
int n,m;///n 是點數,t是邊數 
void init()
{
	memset(vis,0,sizeof(vis));
	memset(dis,inf,sizeof(dis));
	memset(mp,inf,sizeof(mp));
}
void Dijkstra(int s,int e)///s是出發點 e是目的地 
{
	dis[s]=0;
	for(int k=1;k<=n;k++)
	{
		int minw=inf;///記錄用來鬆弛的邊的長度 
		int minv;///記錄用來鬆弛的點
		for(int i=1;i<=n;i++)
		{
			if(dis[i]<minw&&vis[i]==0)
			{
				minw=dis[i];
				minv=i;
			}
		} 
		vis[minv]=1;
		/*if(minv==e) 
		{
			cout<<dis[minv]<<endl;
			return ;
		}*/ 
		//這一部分可以不用也可以用 這是做了一個小小的優化 找到目的地立刻退出,Dijkstra是可以找到從出發點到所有點的最短路
		//如果加上這一句就不能保證其他的能找到了
		for(int i=1;i<=n;i++)
		{
			if(vis[i]==1)//已經確定了的點 
				continue;
			//if(mp[minv][i]==inf) ///表示從鬆弛點到i並沒有邊 所以就不存在鬆弛了
			//	continue
			dis[i]=min(dis[i],dis[minv]+mp[minv][i]); 
		}
	} 
	cout<<dis[e]<<endl;
}
int main()
{
	cin>>m>>n;
	init();
	int a,b,w;
	for(int i=0;i<m;i++)
	{
		cin>>a>>b>>w;
		if(w<mp[a][b])
		{
			mp[a][b]=w;
			mp[b][a]=w;	 
		}
	}
	Dijkstra(1,n);
	return 0;
}