CCPC Harbin 2021 G, Damaged Bicycle

题目描述

Ring Ring Ring … The bell rang at half past six in the morning. After turning off the alarm, George went on to sleep again. When he woke up again, it was seven fifty and there were ten minutes left for class!

George immediately got up from bed, dressed, packed his backpack, brushed his teeth and washed his face. Then, he immediately rushed out of the dormitory and embarked on the road to the teaching building. On the way, he turned on his mobile phone to locate and saw several yellow shared bicycles nearby. Therefore, he headed to a bicycle and took out his mobile phone to scan the QR code on the bicycle. Unfortunately, the bicycle wasn’t unlocked, and a line of words “this bicycle is damaged and can’t be unlocked” was displayed on the screen.

Without riding a bicycle, he was late. What a bad day!

Indeed, some bicycles in the school are damaged, but their location will still be displayed on the app. George always rides faster than he walks, but considering that some bicycles are damaged, if George tries one by one, it may take a long time! In this regard, he has made some modeling, and hopes you can help him find the best strategy.

The campus can be modeled as a graph of n vertices and m bidirected edges, where the i-th edge is wi meters long. George’s dormitory is located at vertex 1 and Guanghua Tower (the teaching building) is at vertex n, so George has to go from vertex 1 to vertex n to take classes. His walking speed is t meters per second and his riding speed is r meters per second. According to the bicycle sharing app, there are k parked bicycles in the campus. The i-th bicycle is located at vertex a i a_i ai, and of probability p i 100 \frac{p_i}{100} 100pi to be damaged according to George’s experience. However, only when George arrives at vertex ai and scans the QR code, can he determine whether the i-th bicycle is damaged or not. As soon as a bicycle is confirmed to be undamaged, George will get on it immediately and will not get off until he reaches vertex n.

Now George wants to save time to get to the classroom. So you, George’s roommate, should help him find an optimal strategy to minimize the mathematical expectation of the time cost on the way, and then output this value. Or you can let him continue sleeping if vertex n is not reachable.

In this problem, you should only consider the time of walking and cycling, and you can assume that the other actions(scanning QR code, getting on, getting off, ⋯) cost no time.

校园可以被看成n个点,m条无向边的图,其中第i条边的长度是wi。你的宿舍在1号点,教学楼在n号点,你想从宿舍去教学楼。你的走路速度是每秒t,骑车速度是每秒r。根据共享单车app,校园内一共有k个停车点。第i个停车点在ai点,但是有pi100的概率,车可能是坏的。但是你只有到达ai点,然后扫描二维码之后才能知道第i辆车是不是好的。如果车是好的,那就可以骑到终点。

问你最优策略下,你最小的到达终点的期望时间是多少。如果到达不了n好点,输出-1。

数据范围:
1 ≤ t , r ≤ 1 0 4 , 1 ≤ n , m ≤ 1 0 5 {1 \leq t, r \leq 10^4, 1\leq n, m \leq 10^5} 1t,r104,1n,m105
1 ≤ u i , v i , ≤ n , u i ≠ v i , 1 ≤ w i ≤ 1 0 4 {1 \leq u_i, v_i, \leq n, u_i \neq v_i, 1 \leq w_i \leq 10^4} 1ui,vi,n,ui=vi,1wi104
0 ≤ k ≤ 18 {0 \leq k \leq 18} 0k18
1 ≤ a i ≤ n , 0 ≤ p i ≤ 100 {1 \leq a_i \leq n, 0 \leq p_i \leq 100} 1ain,0pi100

输入格式

The first line contains two integers t,r(1≤t≤r≤104) — the speed of walking and the speed of riding, respectively.

The second line contains two integers n,m(1≤n,m≤105) — the number of vertices and the number of bidirected edges in the given graph.

Following m lines each contains three integers u i , v i , w i u_i,v_i,w_i ui,vi,wi(1≤ui,vi≤n,ui≠vi,1≤wi≤104), denoting that vertices u,v are connected by a wi-meter-long bidirected edge.

The next line contains a single integer k(0≤k≤18), denoting the number of bicycles in campus.

Following k lines each contains two integers a i , p i a_i,p_i ai,pi(1≤ai≤n,0≤pi≤100), denoting the locations of the bicycles and the percentages of damage probabilities respectively.

It is guaranteed that no two bicycles are in the same vertex.

第一行两个整数t, r, 表示步行速度和骑行速度
第二行两个整数n, m, 表示节点个数和边的个数
接下来m行, 每行三个整数u, v, w, 表示u和v之间有一条w长度的边
下一行为一个整数k, 表示自行车的个数
接下来k行, 每行两个整数a, p, 表示节点a有一辆自行车, 且自行车损坏的概率为p

输出格式

If George cannot reach vertex n, output one line containing one integer “-1”, or output one line containing one real number, denoting the minimum expectation of the time cost on the way.

As long as the relative or absolute error between your answer and the standard answer is within 10−6, your answer will be considered correct.

一个数字, 表示最优策略下, 走到终点n的期望. 如果不能走到n, 则输出-1

思路

我们是肯定要求距离的, 从起点到自行车的距离, 从自行车到终点的距离, 那我们要进行n次dijkstra么? 不需要, 我们发现最终用到的点只有起点, 终点, 自行车点. 而其他的点完全被忽略掉, 最多进行20次dijkstra

最优策略是什么?

我们首先是可以直接步行到终点…, 然后就是去找自行车, 如果自行车是好的, 那么我们就可以直接骑到终点, 如果是坏的呢? 我们可以选择直接走去终点, 或者继续去找下一辆自行车, 不断递归寻找最优解

递归过程

假设我们从i找到一辆坏的自行车, 那我们立马跑去j寻找自行车, 在j的时候, 是一定不会再找i的, 也就是说我们不会再找以前找过的自行车, 那么我们怎么判断自行车是否找过呢? ST数组? 这里注意K是非常小的, 只有18, 所以我们可以使用状态压缩, 用sta二进制中每一个1来表示找过该自行车, 而当前点, 用第二维来表示, 总的表示从j出发, 使用过sta自行车的状态, 到达终点的最优期望

状态转移方程:
d p s t a , u = min ⁡ ( d p s t a , u , ∑ i = 1 k ( 1 − p u ) ⋅ d i s t [ u ] [ n ] / r + p u ⋅ ( d i s t [ u ] [ a i ] / t , d i s t [ s t a ∣ ( 1 < < ( i − 1 ) ) ] [ n ] ) ) dp_{sta, u} = \min(dp_{sta, u}, \sum_{i=1}^{k}(1 - p_u) \cdot dist[u][n] / r + p_u \cdot (dist[u][a_i] / t, dist[sta | (1 << (i - 1))][n])) dpsta,u=min(dpsta,u,i=1k(1pu)dist[u][n]/r+pu(dist[u][ai]/t,dist[sta(1<<(i1))][n]))

最终答案是什么?

最终答案为: f[没有使用单车][起点]. 为什么是没有使用单车, 因为我们这里第一维表示的是到当前点为止, 使用过单车的状态

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
typedef pair<double, int> PII;

const int N = 1e6 + 10;

int t, r;
int n, m;
int h[N], e[N * 2], ne[N * 2], w[N * 2], idx;
int k;
int a[N];
double p[N];
double dist[30][N];
bool st[N];
double f[N][30];

void add(int x, int y, int c) {
    e[idx] = y;
    w[idx] = c;
    ne[idx] = h[x];
    h[x] = idx++;
}

double dfs(int sta, int u) {
    if (f[sta][u]) return f[sta][u];

    double tmp = dist[u][n] / t * p[u] + dist[u][n] / r * (1 - p[u]);
    for (int i = 1; i <= k; i ++ ) {
        if (sta & (1 << (i - 1))) continue;
        tmp = min(tmp, dist[u][n] / r * (1 - p[u]) + p[u] * (dist[u][a[i]] / t + dfs(sta | (1 << (i - 1)), i)));
    }
    f[sta][u] = tmp;
    return f[sta][u];
}

void dijkstra(int start, int id) {
    for (int i = 1; i <= n; i++)
        dist[id][i] = 0x3f3f3f3f, st[i] = false;
    dist[id][start] = 0;

    priority_queue<PII, vector<PII>, greater<PII>> q;
    q.push({dist[id][start], start});

    while (q.size()) {
        auto t = q.top();
        q.pop();

        if (st[t.second]) continue;
        st[t.second] = true;

        for (int i = h[t.second]; i != -1; i = ne[i]) {
            int j = e[i];

            if (dist[id][j] > t.first + w[i]) {
                dist[id][j] = t.first + w[i];
                q.push({dist[id][j], j});
            }
        }
    }
}

void print(int u) {
    for (int i = 1; i <= n; i++)
        cout << dist[u][i] << ' ';
    puts(" -------");
}

int main() {
    memset(h, -1, sizeof h);

    cin >> t >> r;
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int x, y, c;
        cin >> x >> y >> c;
        add(x, y, c);
        add(y, x, c);
    }

    cin >> k;
    for (int i = 1; i <= k; i++) {
        cin >> a[i] >> p[i];
        p[i] /= 100;
        dijkstra(a[i], i);
    }
    p[19] = 1;
    dijkstra(1, 19);
    dijkstra(n, 20);

    if (dist[19][n] == 0x3f3f3f3f) puts("-1");
    else {
        dfs(0, 19);
        printf("%.6lf\n", f[0][19]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值