求
k
k
短路,最短路+可持久化可并堆,。
又是一道论文题。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#ifdef DEBUG
#define debug(orz...) printf(orz)
#define yes(orz...) puts(orz)
#else
#define debug(...) 0
#define yes(...) 0
#endif
#define Min(_A, _B) (_A < _B ? _A : _B)
#define Abs(_A) (_A > 0 ? _A : -(_A))
#define R register
#define Null b
int F()
{
R int x; R char ch;
while(ch = getchar(), ch < '0' || ch > '9'); x = ch - '0';
while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - '0';
return x;
}
const int MaxN = 5010, MaxM = 200010;
int N, M; double E;
struct Edge{ int u, v; double w; } e[MaxM];
int Point[MaxN], Next[MaxM], To[MaxM], q, fa[MaxN]; double W[MaxM];
void Add(R int u, R int v, double w){ Next[++q] = Point[u]; Point[u] = q; To[q] = v; W[q] = w; }
void Add(R int u, R int v){ Next[++q] = Point[u]; Point[u] = q; To[q] = v; }
struct CMP{ int i; double dis; bool operator < (const R CMP i) const { return dis > i.dis; }};
std::priority_queue<CMP> Q;
double dis[MaxN]; bool vis[MaxN], used[MaxM];
void dfs(R int u)
{
vis[u] = 1;
for(R int j = Point[u]; j; j = Next[j])
if(!vis[To[j]] && Abs(dis[To[j]] - W[j] - dis[u]) < 1e-9)
{
fa[To[j]] = u; used[j] = 1;
dfs(To[j]);
}
}
void Dij()
{
Q.push((CMP){N, 0});
for(R int i = 1; i <= N; ++i) dis[i] = 1e9;
while(!Q.empty())
{
while(!Q.empty() && vis[Q.top().i]) Q.pop();
if(Q.empty()) break;
R CMP t = Q.top(); Q.pop();
vis[t.i] = 1; dis[t.i] = t.dis;
for(R int j = Point[t.i]; j; j = Next[j])
if(!vis[To[j]] && dis[t.i] + W[j] < dis[To[j]])
Q.push((CMP){To[j], dis[To[j]] = dis[t.i] + W[j]});
}
memset(vis, 0, sizeof(vis));
dfs(N);
memset(Point, 0, sizeof(Point)); q = 0;
for(R int i = 1; i < N; ++i) Add(fa[i], i);
}
struct Data{ double val; int pos, dis; Data *lson, *rson; } b[300010], *root[MaxN]; int tot;
Data *Merge(Data *A, Data *B)
{
if(A == Null || B == Null) return A == Null ? B : A;
if(A->val > B->val) std::swap(A, B);
A->rson = Merge(A->rson, B);
if(A->rson->dis > A->lson->dis) std::swap(A->rson, A->lson);
A->dis = A->rson->dis + 1;
return A;
}
Data *PMerge(Data *&A, Data *&B)
{
if(A == Null || B == Null) return A == Null ? B : A;
Data *t = b + ++tot, *res;
if(A->val < B->val){ *t = *A; res = B; }
else { *t = *B; res = A; }
t->rson = PMerge(t->rson, res);
if(t->rson->dis > res->lson->dis) std::swap(t->rson, t->lson);
t->dis = t->rson->dis + 1;
return t;
}
void Push(Data *&A, R int pos, R double val)
{
b[++tot] = b[0];
Data *t = b + tot; t->pos = pos; t->val = val;
A = Merge(A, t);
}
void Pop(Data *&A){ A = PMerge(A->lson, A->rson); }
void DFS(R int u)
{
for(R int j = Point[u]; j; j = Next[j])
{
root[To[j]] = PMerge(root[To[j]], root[u]);
DFS(To[j]);
}
}
struct Tmp{ Data *pos; double dis, val; bool operator < (const R Tmp i) const{ return dis > i.dis; }};
std::priority_queue<Tmp> V;
void solve()
{
R int k = 1; E -= dis[1];
if(root[1] != Null) V.push((Tmp){root[1], dis[1] + root[1]->val, root[1]->val});
while(!V.empty())
{
R Tmp t = V.top(); V.pop();
E -= t.dis;
if(E > -1e-9) ++k;
else break;
if(t.dis - t.val + t.pos->val <= E)
{
if(root[t.pos->pos] != Null)
V.push((Tmp){root[t.pos->pos], t.dis + root[t.pos->pos]->val, root[t.pos->pos]->val});
if(t.pos->lson != Null)
V.push((Tmp){t.pos->lson, t.dis - t.val + t.pos->lson->val, t.pos->lson->val});
if(t.pos->rson != Null)
V.push((Tmp){t.pos->rson, t.dis - t.val + t.pos->rson->val, t.pos->rson->val});
}
}
printf("%d\n", k);
}
int main()
{
b[0] = (Data){0, 0, -1, Null, Null};
scanf("%d %d %lf", &N, &M, &E);
for(R int i = 1; i <= M; ++i)
{
R int s = F(), t = F(); R double w;
scanf("%lf", &w);
if(s == N){ --i; --M; continue; }
e[i] = (Edge){s, t, w};
Add(t, s, w);
}
Dij();
for(R int i = 1; i <= N; ++i) root[i] = Null;
for(R Edge *i = e + 1; i <= e + M; ++i) if(!used[i - e])
Push(root[i->u], i->v, dis[i->v] - dis[i->u] + i->w);
DFS(N);
solve();
return 0;
}
A*算法,然而早期写的,写的太差,BZOJ 上被卡空间了,luogu 80+分,复杂度 O(nk) O ( n k ) 。
#include <cstdio>
#include <queue>
#include <cstring>
#define R register
const int MaxN = 5010, MaxM = 200010;
int N, M; double E;
int Point[MaxN], Next[MaxM << 1], To[MaxM << 1], q = 1;
double W[MaxM << 1];
void Add(R int u, R int v, R double w)
{
Next[++q] = Point[u]; Point[u] = q; To[q] = v; W[q] = w;
Next[++q] = Point[v]; Point[v] = q; To[q] = u; W[q] = w;
}
bool vis[MaxN]; int f[MaxN]; double dis[MaxN];
void SPFA()
{
R int head = 0, tail = 1;
for(R int i = 1; i <= N; i++) dis[i] = 100000000;
f[1] = N; vis[N] = 1; dis[N] = 0;
do
{
head = ++head % MaxN;
for(R int j = Point[f[head]]; j; j = Next[j])
{
if((j & 1) && dis[To[j]] > dis[f[head]] + W[j])
{
dis[To[j]] = dis[f[head]] + W[j];
if(!vis[To[j]]) vis[f[tail = ++tail % MaxN] = To[j]] = 1;
}
}
vis[f[head]] = 0;
}
while(head != tail);
}
double s[MaxN]; int Ans;
struct Data
{
double g, h;
int Pos;
bool operator < (Data i) const
{
return h > i.h;
}
bool operator > (Data i) const
{
return h < i.h;
}
};
std::priority_queue<Data> A;
void A_Star()
{
A.push((Data){0, dis[1], 1});
do
{
R Data t = A.top(); A.pop();
if(t.Pos == N) E -= t.g, Ans++;
if(E < 0) return ;
for(R int j = Point[t.Pos]; j; j = Next[j])
if(!(j & 1))
A.push((Data){t.g + W[j], t.g + W[j] + dis[To[j]], To[j]});
}
while(!A.empty());
}
int main()
{
scanf("%d %d %lf", &N, &M, &E);
for(R int i = 1; i <= M; i++)
{
R int s, t; double e;
scanf("%d %d %lf", &s, &t, &e);
Add(s, t, e);
}
SPFA();
A_Star();
printf("%d", Ans - 1);
return 0;
}