題解 P5767 【[NOI1997]最優乘車】

題目node

核心思路:Dijkstra算法c++


首先,我認爲這道題最重要的是建圖,解釋一下我是如何建圖:算法

(題目中說明了是「單程巴士線路」,故圖爲有向圖。)spa

樣例:
aVaHTe.pngcode

(線路的站點就是節點,邊上的數字就是指這條邊屬於哪一條線路)blog

由樣例圖能夠看出,1->7的最少換乘的次數是2次:字符串

1->3 換乘 3->6 換乘 6->7get

但若是隻是單純的做模擬,這道題就失去了意義。it

咱們不妨這樣建圖:模板

將每一條線路的站點,都與這條線路的起點相連。

aVaqFH.png

在同一條線路上的節點,對於最後的換乘數是沒有貢獻的。 也就是說,同一條線路上的點是等價的。

而將每一個點都與起點相連,是由於不能肯定後來讀入的線路是否與先前的線路存在換乘點。 因此乾脆就全連上。

這樣一來,圖中1->n的最短路,就是最小換乘數+1。


而後,講這道題如何讀入。

我看已有的許多的題解中,是用字符串讀入的。大可沒必要。

咱們能夠利用空格換行符來讀入。

像這樣:

while(c!=-1 && c!='\r')	//'\n'
{
	scanf("%d",&a[ ++n ]);
	c=-1;
	scanf("%c",&c);
}

(這個'/r'和洛谷的測評姬有關)


難度評分:建議綠題

理由:這題在Dijkstra模板題的基礎上,增長了對Dijkstra的理解應用,同時這道題卡讀入。

附上代碼:

#include <bits/stdc++.h>
#define MAXN 510
#define MAX 0x3f3f3f3f
using namespace std;
int ori=1,node;	//ori 起點   node 節點數 
int a[5005];	//存輸入 
int dis[MAXN],g[MAXN][MAXN];
bool vis[MAXN]; 
void init()			//初始化 
{
	memset(vis,0,sizeof(vis));
	memset(dis,0,sizeof(dis));
	vis[ori]=1;
	for(int i=1;i<=node;++i)		dis[i] = (i == ori ? 0 : g[ori][i]);
}
void Dijkstra()		//樸素Dijkstra 
{
	int k;	init();
	for(int i=1;i<=node-2;++i)
	{
		int m=MAX;
		for(int j=1;j<=node;++j)
		{
			if(dis[j]<m && vis[j]==0)
			{m=dis[j];	k=j;}
		}
		if(m==MAX)		break;
		vis[k]=1;
		for(int j=1;j<=node;++j)
			if(dis[k]+g[k][j]<dis[j])
				dis[j]=dis[k]+g[k][j];	
	}
	return ;
}
int main()
{
	int edge;
	scanf("%d%d",&edge,&node);
	for(int i=1;i<=node;++i)
		for(int j=1;j<=node;++j)
			g[i][j]=MAX;
	for(int i=1;i<=edge;++i)
	{
		memset(a,0,sizeof(a));
		int n=0;				//計數器 
		char c=1;
		while(c!=-1 && c!='\r')	//'\n'
		{
			scanf("%d",&a[ ++n ]);
			c=-1;
			scanf("%c",&c);
		}
		for(int j=1;j<n;++j)
			for(int k=j+1;k<=n;++k)
				g[ a[j] ][ a[k] ]=1;
	}
	Dijkstra();
	if(dis[node]>=MAX) printf("NO");
    	else printf("%d",dis[node]-1);	//換乘數爲最短距離-1 
	return 0;
}
相關文章
相關標籤/搜索