【暑训排位#3 B】 URAL - 1934 最短路

22 篇文章 0 订阅
18 篇文章 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 n, m — the quantity of islands and known routes between them (2 ≤ n ≤ 10 5; 1 ≤ m ≤ 10 5). The second line contains two integers s and t — the number of island where Jack is and the number of Tortuga (1 ≤ s, t ≤ n; s ≠ t). Each of the following m lines contains three integers — the numbers of islands a i and b i where the route is known and p i — probability to meet Kraken on that route as percentage (1 ≤ a i, b i ≤ n; a i ≠ b i; 0 ≤ p i ≤ 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.
Example
input output
4 4
1 3
1 2 50
2 3 50
1 4 10
4 3 10
3 0.19
1 4 3

题意:边权为1的图,边还有事件A发生概率,要在最短路里面找到事件A发生概率最小的一条走

思路:

1.首先肯定是优先跑最短路。在所有最短路里面找到概率发生最小的。可以将p转化为1-p,求累乘最大。
2.先讨论路径怎么确定,这里用pre数组确定前驱结点,pp数组记录当前结点最大概率累乘(类似d[]数组),如果满足pp[u]*p[i]>pp[v](p[i]为这条边的概率),那v的前驱结点就更新为u。同时概率pp[v]更新。
为什么不能用后继数组来记录下一步选哪个呢?
因为用后继数组的话,思路就变成了确定下一步走到哪,但是我们不能说到v的概率累乘变大了就走它,因为也可能它根本走不到终点。换句话说,用后继数组无法确定下一个结点(最优解)走哪。
而用前驱结点的话,我们能唯一确定把它松弛的那个点一定是它的前驱。
3.个人认为不能用Dijkstra,因为这里的点可能会遍历多次来确定概率最大,而Dijkstra只能每个点走一次(贪心),就会出bug。所以这里还是只采用SPFA。

AC代码:

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int maxn = 1e6+5;
const ll inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') ch = getchar();while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };
const int V = 2e5+500, E=2e5+500;
ll d[V],cost[E];
ll n,m,a,b;
ll head[V],pnt[E],nxt[E],e=0;
ll vis[V];
ll s, t;
double pp[V];
ll pre[V];
double p[V];

void addedge(ll u,ll v,ll c, double p1)
{
    pnt[e]=v;       //当前以u为顶点,c为边长的,到v的一条边
    cost[e]=c;      //存入当前边权值
    p[e] = p1;
    nxt[e]=head[u];     //下一个其实是前一个
    head[u]=e++;        //当前边编号
}

ll SPFA()
{
    queue<ll> q;
    d[s] = 0; pp[s] = 1.0;
    q.push(s);
    vis[s] = 1;
    pre[s] = inf;
    while(!q.empty())
    {
        ll x = q.front(); q.pop();
        vis[x] = 0;
        for(int i=head[x];i!=-1;i = nxt[i])
        {
            ll v = pnt[i];  //if(vis[v]) continue;
            if(d[v]>d[x]+cost[i]||d[v]==d[x]+cost[i]&&pp[x]*p[i] > pp[v])
            {
                pre[v] = x;
                pp[v] = pp[x]*p[i];
                d[v] = d[x] + cost[i];
                if(vis[v]) continue;
                q.push(v);
            }
        }
    }

}

ll ans = 0;
ll res[V];


void dfs(ll cur)
{
    if(cur==inf) return;
    res[ans++] = cur;
    dfs(pre[cur]);
}

int main()
{
    while(cin>>n>>m)
    {
         s = read(), t = read();
        mem(vis,0);mem(head,-1);mem(cost,0); mem(res,0); ans = 0;
        rep(i,1,n) d[i] = inf;
        rep(i,1,m)
        {
            ll x, y, z;
            x = read(), y = read(); z = 1;
            double p1; ll tmp; tmp = read(); p1 = tmp/100.0 ; p1 = 1 - p1;
            addedge(x,y,z,p1);
            addedge(y,x,z,p1);
        }
        SPFA();
        dfs(t);
        printf("%lld %f\n", ans, 1.0-pp[t]);
        for(ll i = ans-1; i>=0 ; i--)
        printf("%lld%c",res[i], i==0?'\n':' ');
    }

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值