1. 程式人生 > >1121】小明的貪心題(Dijkstra最短路 + 最短路條數)

1121】小明的貪心題(Dijkstra最短路 + 最短路條數)

題幹:

小明的貪心題

描述

小明來到青島上學已經一年了,他給青島這座城市畫了一張地圖。在這個地圖上有n個點,小明的起始點為1號點,終點為n號點,並且地圖上的所有邊都是單向的。小明知道從i號點到j號點的時間花費為w分鐘,那麼問題來了,求從1號點到n號的最小時間花費是多少?這個最少花費的路徑有多少條?

輸入

輸入格式:輸入檔案第一行為兩個空格隔開的數n,m,表示這張地圖裡有多少個點及有多少邊的資訊。下面m行,每行三個數I、J、w,表示從I點到J點有道路相連且花費為w.(注意,資料提供的邊資訊可能會重複,不過保證I<>J,1<=I,J<=n)。1<=N<=2100,0<=m<=N*(N-1), 1<=w<=2100.

輸出

輸出格式:輸出檔案包含兩個數,分別是最少花費和花費最少的路徑的總數.兩個不同的最短路方案要求:路徑長度相同(均為最短路長度)且至少有一條邊不重合。若城市N無法到達則只輸出一個(‘No answer’);

輸入樣例 1 

5 4
1 5 4
1 2 2
2 5 2
4 1 1

輸出樣例 1

4 2

輸入樣例 2 

100 1
1 2 1

輸出樣例 2

No answer

解題報告:

     這題比賽的時候坑的我好苦啊,一個小錯誤(不過也確實以前都沒注意這個小地方,大概還是做雙權值的題做少了),最後前十都沒進。。。這麼簡單的一道最短路條數,就因為少了一個vis的if判斷,然後就GG思密達。不過還是有很多地方是值得注意的。比如這題需要去重邊。(直接鄰接矩陣去重邊就可以了,因為資料量2000也不算大)

AC程式碼:

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int INF = 0x3f3f3f3f; 
const ll INFINF = 0x3f3f3f3f3f3f3f3f;
int n,m,top;
int head[5000 +5];
ll dis[5005],ans[5005];
bool vis[5005];
ll maze[5005][5005];
struct Edge{
	int to,ne;
	ll w;
} e[5000000 +5];
struct point {
	int pos;
	ll c;
	point(){}
	point(int pos,ll c):pos(pos),c(c){}
	bool operator <(const point & b) const {
		return c>b.c;
	}
};
void add(int u,int v,ll w) {
	e[++top].to = v;
	e[top].w=w;
	e[top].ne = head[u];
	head[u] = top;
}
void Dijkstra(int u,int v) {
	priority_queue<point> pq; 
	for(int i = 1; i<=n; i++) dis[i] = INFINF;
	memset(vis,0,sizeof vis);
	memset(ans,0,sizeof ans);
	ans[u]=1;
	dis[u] = 0;
	point cur = point(u,0);
	pq.push(cur);
	while(!pq.empty()) {
		point now = pq.top();pq.pop();
//		if(vis[now.pos] == 1) continue;
		vis[now.pos] = 1;
		for(int i = head[now.pos]; i!=-1; i=e[i].ne) {
			if(vis[e[i].to] == 1) continue;
			if(  dis[e[i].to] > dis[now.pos] + e[i].w ) {
				dis[e[i].to] = dis[now.pos] + e[i].w;
				ans[e[i].to] = ans[now.pos];
				pq.push(point(e[i].to,dis[e[i].to] ) );	
			}
			else if(dis[e[i].to] == dis[now.pos] + e[i].w) {
				ans[e[i].to] += ans[now.pos];
			}
		} 
	}
	if(dis[v] == INFINF) puts("No answer");
	else {
		printf("%lld %lld\n",dis[v],ans[v]);
	}
} 
int main()
{
	int a,b;
	ll w;
	while(~scanf("%d%d",&n,&m)) {
		top=0;
		memset(head,-1,sizeof head);
//		memset(maze,INF,sizeof maze);
		for(int i = 1; i<=n; i++) {
			for(int j = 1; j<=n; j++) {
				maze[i][j] = INFINF;
			}
		}
		for(int i = 1; i<=m; i++) {
			scanf("%d %d %lld",&a,&b,&w);
			if(maze[a][b]>w) maze[a][b]=w;
		}
		for(int i = 1; i<=n; i++) {
			for(int j = 1; j<=n; j++) {
				if(maze[i][j]<10000) {
					add(i,j,maze[i][j]);
				}
			}
		}
		Dijkstra(1,n); 
	}
	return 0 ;
}
//5 4
//1 5 4
//1 2 2
//2 5 2
//4 1 1

AC程式碼2:

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int INF = 0x3f3f3f3f; 
const ll INFINF = 0x3f3f3f3f3f3f3f3f;
int n,m,top;
int head[5000 +5];
ll dis[5005],ans[5005];
bool vis[5005];
ll maze[5005][5005];
struct Edge{
	int to,ne;
	ll w;
} e[5000000 +5];
struct point {
	int pos;
	ll c;
	point(){}
	point(int pos,ll c):pos(pos),c(c){}
	bool operator <(const point & b) const {
		return c>b.c;
	}
};
void add(int u,int v,ll w) {
	e[++top].to = v;
	e[top].w=w;
	e[top].ne = head[u];
	head[u] = top;
}
void Dijkstra(int u,int v) {
	priority_queue<point> pq; 
	for(int i = 1; i<=n; i++) dis[i] = INFINF;
	memset(vis,0,sizeof vis);
	memset(ans,0,sizeof ans);
	ans[u]=1;
	dis[u] = 0;
	point cur = point(u,0);
	pq.push(cur);
	while(!pq.empty()) {
		point now = pq.top();pq.pop();
		if(vis[now.pos] == 1) continue;
		vis[now.pos] = 1;
		for(int i = head[now.pos]; i!=-1; i=e[i].ne) {
//			if(vis[e[i].to] == 1) continue;
			if(  dis[e[i].to] > dis[now.pos] + e[i].w ) {
				dis[e[i].to] = dis[now.pos] + e[i].w;
				ans[e[i].to] = ans[now.pos];
				pq.push(point(e[i].to,dis[e[i].to] ) );	
			}
			else if(dis[e[i].to] == dis[now.pos] + e[i].w) {
				ans[e[i].to] += ans[now.pos];
			}
		} 
	}
	if(dis[v] == INFINF) puts("No answer");
	else {
		printf("%lld %lld\n",dis[v],ans[v]);
	}
} 
int main()
{
	int a,b;
	ll w;
	while(~scanf("%d%d",&n,&m)) {
		top=0;
		memset(head,-1,sizeof head);
//		memset(maze,INF,sizeof maze);
		for(int i = 1; i<=n; i++) {
			for(int j = 1; j<=n; j++) {
				maze[i][j] = INFINF;
			}
		}
		for(int i = 1; i<=m; i++) {
			scanf("%d %d %lld",&a,&b,&w);
			if(maze[a][b]>w) maze[a][b]=w;
		}
		for(int i = 1; i<=n; i++) {
			for(int j = 1; j<=n; j++) {
				if(maze[i][j]<10000) {
					add(i,j,maze[i][j]);
				}
			}
		}
		Dijkstra(1,n); 
	}
	return 0 ;
}
//5 4
//1 5 4
//1 2 2
//2 5 2
//4 1 1

總結:

   所以保險起見,還是兩個if剪枝都寫上吧。