Sightseeing/观光 (dp+最短路)

8 篇文章 0 订阅
3 篇文章 0 订阅

Description

“您的个人假期”旅行社组织了一次比荷卢经济联盟的巴士之旅。

比荷卢经济联盟有很多公交线路。

每天公共汽车都会从一座城市开往另一座城市。

沿途汽车可能会在一些城市(零或更多)停靠。

旅行社计划旅途从 S 城市出发,到 F 城市结束。

由于不同旅客的景点偏好不同,所以为了迎合更多旅客,旅行社将为客户提供多种不同线路。

游客可以选择的行进路线有所限制,要么满足所选路线总路程为 S 到 F 的最小路程,要么满足所选路线总路程仅比最小路程多一个单位长度。

如上图所示,如果 S=1,F=5,则这里有两条最短路线 1→2→5,1→3→5,长度为 6;有一条比最短路程多一个单位长度的路线 1→3→4→5,长度为 7。

现在给定比荷卢经济联盟的公交路线图以及两个城市 S 和 F,请你求出旅行社最多可以为旅客提供多少种不同的满足限制条件的线路。

Input

第一行包含整数 TT,表示共有 TT 组测试数据。

每组数据第一行包含两个整数 NN 和 MM,分别表示总城市数量和道路数量。

接下来 MM 行,每行包含三个整数 A,B,LA,B,L,表示有一条线路从城市 AA 通往城市 BB,长度为 LL。

需注意,线路是 单向的,存在从 AA 到 BB 的线路不代表一定存在从 BB 到 AA 的线路,另外从城市 AA 到城市 BB 可能存在多个不同的线路。

接下来一行,包含两个整数 SS 和 FF,数据保证 SS 和 FF 不同,并且 S、FS、F 之间至少存在一条线路。

Output

每组数据输出一个结果,每个结果占一行。

数据保证结果不超过 109109。

数据范围

2≤N≤10002≤N≤1000,
1≤M≤100001≤M≤10000,
1≤L≤10001≤L≤1000,
1≤A,B,S,F≤N1≤A,B,S,F≤N

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

思路:用dijkstra+dp,类似平时求最大值和次大值一样,如果找到一个数大于最大值,则让最小值等于最大值,再更新最大值;如果找到一个数大于次大值但小于最大值则更新次大值。

在dijkstra的运算中,不管是最大值还是次大值,只要被更新就要入队,这里我的理解是dp里要充分考虑所有情况。

#include<bits/stdc++.h>
using namespace std;

#define N 1020
#define M 10020

int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

struct Ver {
	int ver, type, dist;
	bool operator>(const Ver& w)const {
		return dist > w.dist;
	}
};
int t, n, m, s, f;
int dist[N][2], st[N][2], cnt[N][2];//0表示最短路状态,1表示次短路状态

int dijkstra() {
	memset(dist, 0x3f, sizeof dist);
	memset(st, 0, sizeof st);
	memset(cnt,0,sizeof cnt);
	dist[s][0] = 0, cnt[s][0] = 1;
	priority_queue<Ver, vector<Ver>, greater<Ver>> heap;
	heap.push({ s,0,0 });

	while (heap.size()) {
		Ver t = heap.top();
		heap.pop();
		int ver = t.ver, type = t.type, distance = t.dist;

		if (st[ver][type])continue;
		st[ver][type] = 1;

		for (int i = h[ver]; i != -1; i = ne[i]) {
			int j = e[i];
			if (dist[j][0] > distance + w[i]) {//找到比最短路还短的路径
				dist[j][1] = dist[j][0], cnt[j][1] = cnt[j][0];
				heap.push({ j,1,dist[j][1] });
				dist[j][0] = distance + w[i], cnt[j][0] = cnt[ver][type];
				heap.push({ j,0,dist[j][0] });
			}
			else if (dist[j][0] == distance + w[i])//找到与最短路相等的路径
				cnt[j][0] += cnt[ver][type];
			else if (dist[j][1] > distance + w[i]) {//找到大于次最短路小于最短路的路径
				dist[j][1] = distance + w[i], cnt[j][1] = cnt[ver][type];
				heap.push({ j,1,dist[j][1] });
			}
			else if (dist[j][1] == distance + w[i])//找到等于次最短路的路径
				cnt[j][1] += cnt[ver][type];
		}
	}
	int res = cnt[f][0];
	if (dist[f][0] == dist[f][1] - 1)res += cnt[f][1];
	return res;
}

int main() {
	scanf("%d", &t);
	while (t--) {
		memset(h, -1, sizeof h);
		idx = 0;
		scanf("%d%d", &n, &m);
		int a, b, c;
		for (int i = 0; i < m; i++) {
			scanf("%d%d%d", &a, &b, &c);
			add(a, b, c);
		}
		scanf("%d%d", &s, &f);
		int ans = dijkstra();
		printf("%d\n", ans);
	}		
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值