(intermediate)次短路 UVA 10342 - Always Late

Always Late

Ajmat:Have you noticed one member of team 13 comes late in almost every contest?
Nejhum:  You mean the team of Mahbub, Moazzem and Yeamin? What's the problem with them?
Ajmat:All of them lives far away from BUET, and they always avoid the shortest path to BUET.
Nejhum:Are you kidding? Why would they do so? A computer science student won't ever do that.
Ajmat:They always avoids the shortest path. They believe that they always face the worst traffic jam on their shortest way to BUET.
Nejhum:That sounds crazy!
Ajmat:They are more crazy than you think they are. They always try to use the path whose length is smaller than or equal to that of any path to BUET except the shortest one. And for that, they sometimes visit the same junction more than once.
Nejhum:But they are not using the longest path. Then why are they late almost everyday?
Ajmat:That's because they have to spend a lot of time to find out which of the paths meet their criteria. Perhaps they don't know how to find out the second-shortest path.
Nejhum:I think we should solve this real problem in today's contest, instead of solving imaginary ones.
Ajmat:Let's try.

Input

The first line of each test case contains two integers: n (the number of junctions, 1 < n < 100) and r (the number of bi-directional roads connecting these junctions). The junctions are numbered with 0, 1, ..., n-1. Each of the next r lines (one for each road) contains three integers: two junction-numbers that the corresponding road connects and the length of the road in kilometers. The next line contains an integer q, the number of queries. Each of the next q lines contains two junction-numbers. There is a blank line after the q queries. There is at most 1 road between each junction pair. A road always connects two different junctions. Length of a road is not less than 1km and not more than 100km.
 
Input is terminated by EOF.
 

Output

For each set of output, print the set # (1, 2, ? ) followed by q lines, one for each query, each containing the length of the second-shortest path between the corresponding junctions. However, for the unsolvable queries, print a '?'.
 

Sample Input

4 3
0 1 12
0 2 20
1 2 15
3
0 1
0 2
0 3

4 3
0 1 11
0 2 20
1 2 15
3
0 1
0 2
0 3

Sample Output

Set #1
35
27
?
Set #2
33
26
?

Mustaq Ahmed. 12-07-2002.


题意:最是找次短路,每个点可以经过不止一次。

思路:一开始先用floyd算出两两之间的最短距离,然后用dfs算出次短的,dfs的时候判断dist+w[x][t] < ans[s][t](保证比最短路大的情况下)更新ans的值,最后得到的就是s到t的次短路。

代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
using namespace std;
const int inf = 1e8;
const int maxn = 100+5;
int n , m , q , ptr;

struct Node
{
	int v;
	int w;
	Node *next;
}edge[maxn*maxn] , *first[maxn];

int w[maxn][maxn];
int ans[maxn][maxn];

void init()
{
	memset(first,0,sizeof(first));
	ptr = 0;
	for (int i = 0 ; i < n ; ++i) 
		for (int j = 0 ; j < n ; ++j)
			ans[i][j] = w[i][j] = inf;
}

void add(int x,int y,int w)
{
	edge[++ptr].v = y;
	edge[ptr].w = w;
	edge[ptr].next = first[x];
	first[x] = &edge[ptr];
}

void dfs(int s,int t,int x ,int dist)
{
	if (ans[s][t] <= dist + w[x][t]) return;
	if (w[s][t] < dist+w[x][t]) 
		ans[s][t] = min(ans[s][t],dist+w[x][t]);
	for (Node * p = first[x] ; p ; p=p->next)
	{
		int y = p->v;
		dfs(s,t,y,dist+p->w);
	}
}

void input()
{
	int u , v;
	while (m--)
	{
		scanf("%d%d",&u,&v);
		scanf("%d",&w[u][v]);
		w[v][u] = w[u][v];
		add(u,v,w[u][v]);
		add(v,u,w[v][u]);
	}
	for (int i = 0 ; i < n ; ++i) w[i][i] = 0;
	for (int k = 0 ; k < n ; ++k)
		for (int i = 0 ; i < n ; ++i) 
			for (int j = 0 ; j < n ; ++j) 
				w[i][j] = min(w[i][j],w[i][k]+w[k][j]);


	for (int i = 0 ; i < n ; ++i) 
		for (int j = 0 ; j < n ; ++j) if (w[i][j] != inf) 
			dfs(i,j,i,0);

}


void solve()
{
	scanf("%d",&q);
	while (q--)
	{
		int u , v;
		scanf("%d%d",&u,&v);
		if (u < 0 || v < 0 || u >= n || v >= n || ans[u][v]>=inf) printf("?\n");
		else printf("%d\n",ans[u][v]);
	}
}

int main()
{
	int k = 0;
	while (scanf("%d%d",&n,&m)==2)
	{
		++k;
		init();
		input();
		printf("Set #%d\n",k);
		solve();
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值