[多权值最短路]Black Spot URAL1934

48 篇文章 0 订阅

Bootstrap: Jones's terrible leviathan will find you and drag the Pearl back to the depths and you along with it.
Jack: Any idea when Jones might release said terrible beastie?
Bootstrap: I already told you, Jack. Your time is up. It comes now, drawn with ravenous hunger to the man what bears the black spot.

Captain Jack Sparrow has got a black spot on his hand and he avoids going to high seas because sea monster Kraken is waiting there for him. But he can’t stay in his place due to his freedom-loving nature. And now Jack is going to Tortuga.

There are n islands in the Caribbean Sea. Jack is going to reach Tortuga, sailing from island to island by routes that allow him to be in the high seas for a short time. Jack knows such routes for some pairs of islands, but they could also be dangerous for him. There is a probability to meet Kraken on each route.

Jack is in a hurry and he wants to reach Tortuga visiting as small number of islands as possible. If there are several variants of such paths he wants to choose a path with the least probability of meeting Kraken. But Jack will be satisfied with any path with minimal number of islands if the probability of meeting Kraken on this path differs from the minimal one in no more than 10−6. Help Jack find such path.

Input

The first line contains two integers nm — the quantity of islands and known routes between them (2 ≤ n ≤ 105; 1 ≤ m ≤ 105). The second line contains two integers s and t — the number of island where Jack is and the number of Tortuga (1 ≤ st ≤ ns ≠ t). Each of the following m lines contains three integers — the numbers of islands ai and bi where the route is known and pi — probability to meet Kraken on that route as percentage (1 ≤ aibi ≤ nai ≠ bi; 0 ≤ pi ≤ 99). No more than one route is known between each pair of islands.

Output

In the first line output k — number of islands along the path and p — probability to meet Kraken on that path. An absolute error of p should be up to 10−6. In the next line output k integers — numbers of islands in the order of the path. If there are several solutions, output any of them.

Sample 1

InputcopyOutputcopy
4 4
1 3
1 2 50
2 3 50
1 4 10
4 3 10
3 0.19
1 4 3

题意: 有n座岛屿,m条航线,同时每条航线有概率出现海怪,输出从起点s到终点t的最短路径,该路径要保证遇到海怪概率最小。

分析: 要求的路径首先是最短路,其次才是遇到海怪概率最小的路径。求路径上遇到海怪的概率可以用反面事件,1-每段路都没遇到海怪的概率,后者是每段路概率乘积。之后可以用p数组维护从起点到各点最短路径上都没遇到海怪的概率,这样就成了一个多权值最短路问题,与普通最短路差别就在于dis[now]+w == dis[to]时,如果此时从当前点到达下一个点会使得第二个权值更优那就更改路线,否则不必改动。

具体代码如下: 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#define pii pair<int, int>
using namespace std;
//首先需要路径最短,其次需要遇到怪物概率最低 
int n, m, s, t, dis[100005], head[100005], cnt, pre[100005], st[100005];
bool vis[100005];
double p[100005]; 
struct edge
{
	int to, w, next;
}e[200005];

void add(int u, int v, int w)
{
	e[++cnt].to = v;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt;
}

void dijkstra()
{
	dis[s] = 1;
	p[s] = 1.0;
	priority_queue<pii, vector<pii>, greater<pii> > a;
	a.push(make_pair(dis[s], s));
	while(a.size())
	{
		int now = a.top().second;
		a.pop();
		if(vis[now])
			continue;
		vis[now] = true;
		for(int i = head[now]; i; i = e[i].next)
		{
			int to = e[i].to, w = e[i].w;
			if(dis[now]+1 < dis[to])
			{
				dis[to] = dis[now]+1;
				pre[to] = now;
				p[to] = p[now]*(100.0-w)/100.0;
				a.push(make_pair(dis[to], to));
			}
			else if(dis[now]+1 == dis[to])
			{
				if(p[now]*(100.0-w)/100.0 > p[to])
				{
					p[to] = p[now]*(100.0-w)/100.0;
					pre[to] = now;
				}
			}
		}
	}
}

signed main()
{
	cin >> n >> m >> s >> t;
	for(int i = 1; i <= m; i++)
	{
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w), add(v, u, w);
	}
	memset(dis, 0x3f, sizeof dis);
	dijkstra();
	printf("%d %.10f\n", dis[t], 1.0-p[t]);
	int top = 0, now = t;
	while(pre[now])
	{
		st[++top] = now;
		now = pre[now];
	}
	st[++top] = s;
	for(int i = top; i >= 1; i--)
		printf("%d ", st[i]);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值