BZOJ3627 [JLOI2014]路径规划

题意:求期望红绿灯时间下,途径若干加油站,经过最多若干个红绿灯,起点与终点的最短路。


思路:每个有红绿灯的节点通过时间怎么算呢?事实上t=red*red/2/(red+green),然后把这个时间附加到节点的出边上。

随后我们建立分层图,第i层表示经过了i个红绿灯时,从源点到该点的最短路径长度。

如果没有油量限制,那么我们直接跑最短路就行了。

注意到加油站很少,于是我们枚举以每个加油站为起点,向其他加油站经过若干个红绿灯的最短路径。若此长度不大于最大油量,那么可以直接转移。

我们用上述信息构造新图,依旧是分层图,可是每一层仅有50个点,且没有油量限制。

一次最短路出解。


Code:

#include <map>
#include <queue>
#include <string>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
 
typedef double f2;
#define _abs(x) ((x)>0?(x):-(x))
 
#define N 10010
int n, m, dep, lim, cost;
bool isGas[N];
f2 length[N];
map<string, int> M;
int id, S, T;
 
int Point_id, lab[11][N];
 
struct Node {
    int lab;
    f2 dis;
    Node(int _lab = 0, f2 _dis = 0):lab(_lab),dis(_dis){}
    bool operator < (const Node &B) const {
        return dis < B.dis;
    }
};
void swap(Node &x, Node &y) {
    Node tmp = x;
    x = y;
    y = tmp;
}
 
struct Heap {
    Node a[110010];
    int top;
    Heap():top(0){}
    void up(int x) {
        for(; x != 1; x >>= 1)
            if (a[x] < a[x >> 1])
                swap(a[x], a[x >> 1]);
            else
                break;
    }
    void down(int x) {
        int son;
        for(; (x << 1) <= top; ) {
            son=(((x<<1)==top)||(a[x<<1]<a[(x<<1)|1]))?(x<<1):((x<<1)|1);
            if (a[son] < a[x]) {
                swap(a[son], a[x]);
                x = son;
            }
            else
                break;
        }
    }
    void insert(const Node &x) {
        a[++top] = x;
        up(top);
    }
    Node Min() {
        return a[1];
    }
    void pop() {
        a[1] = a[top--];
        down(1);
    }
}H;
 
queue<int> q;
struct Graph {
    int head[110010], next[450010], end[450010], ind;
    f2 len[450010], dis[110010];
    bool inpath[110010];
    void reset() {
        ind = 0;
        memset(head, -1, sizeof head);
    }
    void addedge(int a, int b, f2 _len) {
        int q = ind++;
        end[q] = b;
        next[q] = head[a];
        head[a] = q;
        len[q] = _len;
    }
    void spfa(int S) {
        register int i, j;
        for(i = 1; i <= Point_id; ++i)
            dis[i] = 1e10;
        dis[S] = 0;
        memset(inpath, 0, sizeof(inpath));
        H.top = 0, H.insert(Node(S, 0));
        Node tmp;
        while(H.top) {
            tmp = Node(0, 0);
            while(H.top) {
                tmp = H.Min();
                H.pop();
                if (!inpath[tmp.lab] && _abs(tmp.dis - dis[tmp.lab]) <= 1e-6)
                    break;
            }
            if (tmp.lab == 0)
                break;
            inpath[tmp.lab] = 1;
            for(j = head[tmp.lab]; j != -1; j = next[j])
                if (dis[end[j]] > dis[tmp.lab] + len[j]) {
                    dis[end[j]] = dis[tmp.lab] + len[j];
                    H.insert(Node(end[j], dis[end[j]]));
                }
        }
    }
}G1, G2;
 
void Getaddedge(int a, int b, int len) {
    int j;
    if (_abs(length[b]) > 1e-7)
        for(j = 0; j < dep; ++j)
            G1.addedge(lab[j][a], lab[j + 1][b], len + length[b]);
    else
        for(j = 0; j <= dep; ++j)
            G1.addedge(lab[j][a], lab[j][b], len);
}
 
int Gases[101], top;
 
int main() {    
    scanf("%d%d%d%d%d", &n, &m, &dep, &lim, &cost);
     
    register int i, j, k, p;
    for(i = 0; i <= dep; ++i)
        for(j = 1; j <= n; ++j)
            lab[i][j] = ++Point_id;
 
    string s, s1, s2;
    int red, green, num;
    for(i = 1; i <= n; ++i) {
        cin >> s >> red >> green;
        num = M[s];
        if (!num)
            M[s] = num = ++id;
        if (s == "start")
            S = num;
        else if (s == "end")
            T = num;
        else if (s.find("gas") != string::npos)
            isGas[num] = 1;
        if (red)
            length[num] = red * red / ((f2)2 * (red + green));
    }
     
    G1.reset();
    G2.reset();
    int a, b, len;
    for(i = 1; i <= m; ++i) {
        cin >> s1 >> s2 >> s >> len;
        a = M[s1], b = M[s2];
        Getaddedge(a, b, len);
        Getaddedge(b, a, len);
    }
     
    isGas[S] = isGas[T] = 1;
    for(i = 1; i <= n; ++i)
        if (isGas[i])
            Gases[++top] = i;
 
    for(i = 1; i <= top; ++i) {
        G1.spfa(lab[0][Gases[i]]);
        for(j = 1; j <= top; ++j) {
            if (i == j)
                continue;
            f2 add = (Gases[j] != S && Gases[j] != T) ? cost : 0;
            for(k = 0; k <= dep; ++k)
                if (G1.dis[lab[k][Gases[j]]] <= lim)
                    for(p = 0; p + k <= dep; ++p)
                        G2.addedge(lab[p][Gases[i]], lab[p + k][Gases[j]], G1.dis[lab[k][Gases[j]]] + add);
        }
    }
     
    G2.spfa(lab[0][S]);
     
    f2 res = 1e10;
    for(i = 0; i <= dep; ++i)
        res = min(res, G2.dis[lab[i][T]]);
     
    printf("%.3lf", res);
     
    return 0;
}


你可能感兴趣的:(BZOJ3627 [JLOI2014]路径规划)