Sightseeing --HDU-1688&POJ-3463最短路与次短路的条数

Time Limit: 2000MS Memory Limit: 65536K

 

Description

Tour operator Your Personal Holiday organises guided bus trips across the Benelux. Every day the bus moves from one city S to another city F. On this way, the tourists in the bus can see the sights alongside the route travelled. Moreover, the bus makes a number of stops (zero or more) at some beautiful cities, where the tourists get out to see the local sights.

Different groups of tourists may have different preferences for the sights they want to see, and thus for the route to be taken from S to F. Therefore, Your Personal Holiday wants to offer its clients a choice from many different routes. As hotels have been booked in advance, the starting city S and the final city F, though, are fixed. Two routes from S to F are considered different if there is at least one road from a city A to a city B which is part of one route, but not of the other route.

There is a restriction on the routes that the tourists may choose from. To leave enough time for the sightseeing at the stops (and to avoid using too much fuel), the bus has to take a short route from S to F. It has to be either a route with minimal distance, or a route which is one distance unit longer than the minimal distance. Indeed, by allowing routes that are one distance unit longer, the tourists may have more choice than by restricting them to exactly the minimal routes. This enhances the impression of a personal holiday.

                                                                            

For example, for the above road map, there are two minimal routes from S = 1 to F = 5: 1 → 2 → 5 and 1 → 3 → 5, both of length 6. There is one route that is one distance unit longer: 1 → 3 → 4 → 5, of length 7.

Now, given a (partial) road map of the Benelux and two cities S and F, tour operator Your Personal Holiday likes to know how many different routes it can offer to its clients, under the above restriction on the route length.

Input

The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:

  • One line with two integers N and M, separated by a single space, with 2 ≤ N ≤ 1,000 and 1 ≤ M ≤ 10, 000: the number of cities and the number of roads in the road map.

  • M lines, each with three integers AB and L, separated by single spaces, with 1 ≤ AB ≤ NA ≠ B and 1 ≤ L ≤ 1,000, describing a road from city A to city B with length L.

    The roads are unidirectional. Hence, if there is a road from A to B, then there is not necessarily also a road from B to A. There may be different roads from a city A to a city B.

  • One line with two integers S and F, separated by a single space, with 1 ≤ SF ≤ N and S ≠ F: the starting city and the final city of the route.

    There will be at least one route from S to F.

Output

For every test case in the input file, the output should contain a single number, on a single line: the number of routes of minimal length or one distance unit longer. Test cases are such, that this number is at most 109 = 1,000,000,000.

Sample Input

2
5 8
1 2 3
1 3 2
1 4 5
2 3 1
2 5 3
3 4 2
3 5 4
4 5 3
1 5
5 6
2 3 1
3 2 1
3 1 10
4 5 2
5 2 7
5 2 7
4 1

Sample Output

3
2

Hint

The first test case above corresponds to the picture in the problem description.

 


题目大意:给你一些路让你求最短路的条数,如果次短路的长度比最短路大1,那么输出最短路的条数与次短路的条数之和。

。。。。本题需要注意的是有向边,且有重边,而这里的重边由于次短路的关系并不能直接去掉(相当于A到B右两条直达的路)所以邻接矩阵存图是不行的,那么只能使用邻接表了。

由于本题的数据不是很大,所以可以直接用一般的Dij算法就可以了,只不过由于要求次短路,所以对最外层的for扩大一倍就好了。

接下来就是更新最短路、次短路以及他们的条数了。

可以明确的是我们首先更新的是最短路。那么先处理最短路就好了(设dis[x][id]为次短路和最短路的距离id=0表示最短路,1为次短路)那么我们按照一般的Dij算法直接将dis[s][0]=0,numb[s][0]=1;这也就是初始状态了。接下来就是跑Dij最短路了:

for (int j = 1; j <= n; j++) {
	if (!vis[j][0] && tmp > dis[j][0]) {
		k = j;
		flag = 0;
		tmp = dis[j][0];
	} 
	else if (!vis[j][1] && tmp > dis[j][1]) {
		k = j;
		flag = 1;
		tmp = dis[j][1];
	}
}

由于第一次我们只将最短路搞了一下所以刚开始也就只会跑第一个if。。。

接下来就是常规操作了,不过更新的时候注意一下就好了:

1.当当前路径的值小于最短路时,将最短路的长度和数量赋给次短路,最短路更新为当前的值,且条数更新;

2.当前的路径的长度等于最短路时,更新最短路的数量;

3.当前的路径的长度小于次短路时,更新次短路的数量和长度;

4.当前路径的长度等于次短路时,更新次短路的数量。

以下是AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int mac = 1e4 + 10;
typedef long long ll;
const ll inf = 1e16 + 10;
int n, m;
struct node
{
	int u, v, w, next;
};
node eg[mac << 1];
int head[mac], num, s, f;
ll dis[mac][2];
int nb[mac][2], vis[mac][2];
void add(int u, int v, int w);
int Dij();
int main()
{
	//freopen("in.txt", "r", stdin);
	int t;
	scanf("%d", &t);
	while (t--) {
		num = 0;
		scanf("%d%d", &n, &m);
		int u, v, w, ans;
		memset(head, -1, sizeof(head));
		for (int i = 1; i <= m; i++) {
			scanf("%d%d%d", &u, &v, &w);
			add(u, v, w);
		}
		scanf("%d%d", &s, &f);
		ans = Dij();
		printf("%d\n", ans);
	}

	return 0;
}
void add(int u, int v, int w)
{
	eg[++num].u = u; eg[num].v = v; eg[num].w = w;
	eg[num].next = head[u]; head[u] = num;
}
int Dij()
{
	for (int i = 1; i <= n; i++) dis[i][0] = dis[i][1] = inf;
	memset(vis, 0, sizeof(vis));
	memset(nb, 0, sizeof(nb));
	dis[s][0] = 0; nb[s][0] = 1;
	int flag=0;
	for (int i = 1; i <= n * 2-1; i++) {
		int tmp = inf, k=0;
		for (int j = 1; j <= n; j++) {
			if (!vis[j][0] && tmp > dis[j][0]) {
				k = j; flag = 0; tmp = dis[j][0];
			}
			else if (!vis[j][1] && tmp > dis[j][1]) {
				k = j; flag = 1; tmp = dis[j][1];
			}
		}
		if (tmp == inf) break;
		vis[k][flag] = 1;
		for (int j = head[k]; j != -1; j = eg[j].next) {
			int v = eg[j].v, w = eg[j].w;
			if (dis[v][0] > tmp + w) {
				dis[v][1] = dis[v][0];
				nb[v][1] = nb[v][0];
				dis[v][0] = tmp + w;
				nb[v][0] = nb[k][flag];
			}
			else if (dis[v][0] == tmp + w)
				nb[v][0] += nb[k][flag];
			else if (dis[v][1] > tmp + w)
				dis[v][1] = tmp + w, nb[v][1] = nb[k][flag];
			else if (dis[v][1] == tmp + w)
				nb[v][1] += nb[k][flag];
		}
	}
	if (dis[f][1] == dis[f][0] + 1)
		nb[f][0] += nb[f][1];
	return nb[f][0];
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值