您的位置:首页 > 其它

BZOJ3627 [JLOI2014]路径规划

2017-06-21 09:52 274 查看
题意:求期望红绿灯时间下。途径若干加油站。经过最多若干个红绿灯,起点与终点的最短路。

思路:每一个有红绿灯的节点通过时间怎么算呢?其实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
;
f2 length
;
map<string, int> M;
int id, S, T;

int Point_id, lab[11]
;

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: