先把代码放这, 解释下次再说
其实让我很不解明明是个 (A^*) 板子为什么还要卡裸 (A^*).. 给我这个只想先打个裸 (A^*) 看看自己理解的对不对 就是懒 的菜鸡带来了极大不便... 然后就直接特判了
其实一想也算是个提醒吧: 裸 (A^*) 的确很费空间.
注: 不特判打正解需要可持久化可并堆
代码:
# include <iostream>
# include <cstring>
# include <cstdio>
# include <queue>
# define MAXM 2000005
# define MAXN 5005
using namespace std;
int n, m;
double ener;
// Edge Section
struct edge{
int u, v, next;
double w;
bool forw; // forw = 1 为正图上的边
}e[MAXM<<1];
int hd[MAXM<<1], cntE;
void AddE(int u, int v, double w){
e[++cntE].u = u, e[cntE].v = v, e[cntE].w = w, e[cntE].forw = 1, e[cntE].next = hd[u], hd[u] = cntE;
e[++cntE].u = v, e[cntE].v = u, e[cntE].w = w, e[cntE].forw = 0, e[cntE].next = hd[v], hd[v] = cntE;
} // 同时新建正反图的边
// Dij Section
struct node{
int id;
double val;
bool operator < (const node that) const{
return this->val < that.val;
}
bool operator > (const node that) const{
return this->val > that.val;
}
};
priority_queue<node, vector<node>, greater<node> >qDij;
double h[MAXN];
bool vis[MAXN];
void Dij(int from){
for(int i = 1; i <= n; i++){
h[i] = 1e9, vis[i] = 0;
}
h[from] = 0;
qDij.push((node){from, 0});
while(!qDij.empty()){
node tmp = qDij.top();
qDij.pop();
if(vis[tmp.id]){
continue;
}
vis[tmp.id] = 1;
for(int i = hd[tmp.id]; i; i = e[i].next){
if(!e[i].forw){
if(h[tmp.id] + e[i].w < h[e[i].v]){
h[e[i].v] = h[tmp.id] + e[i].w;
qDij.push((node){e[i].v, h[e[i].v]});
}
}
}
}
} // 在反图上跑迪杰, 从终点开始
// A* Section
struct star{
int id;
double g, f;
bool operator < (const star that) const{
return this->g+this->f < that.g+that.f;
}
bool operator > (const star that) const{
return this->g+this->f > that.g+that.f;
}
};
priority_queue<star, vector<star>, greater<star> >qAs;
int cnt[MAXN]; // 记录某个点到了几次用于及时跳出
int ans = 0 ;
void Astar(int lim){
if(h[1] > 1e9-5) return;
star tmp, nxt;
tmp.id = 1, tmp.g=0, tmp.f = 0;
qAs.push(tmp);
while(!qAs.empty()){
tmp = qAs.top(); qAs.pop();
if(tmp.g > ener) return; // 特判是否到达最大取值
cnt[tmp.id]++;
if(cnt[tmp.id] > lim) continue; // 特判优化
if(tmp.id == n){
ener -= tmp.g;
ans++;
continue;
} // 每次搜到终点的答案都可以记录, 第 i 次就是第 i 短路
// 相对于第 i 次搜索来说, 就是最短的
// 因为更短的方法已经被弹出去了
for(int i = hd[tmp.id]; i; i = e[i].next){
if(e[i].forw){
nxt.id = e[i].v;
nxt.f = h[nxt.id];
nxt.g = tmp.g + e[i].w;
qAs.push(nxt);
} // 延展到的点压入堆, 关键字为 g+h
}
}
} // g 为实际, h 为预估
// Main Function
int main(){
scanf("%d%d%lf", &n, &m, &ener);
int ua, va; double wa;
for(int i = 1; i <= m; i++){
scanf("%d%d%lf", &ua, &va, &wa);
AddE(ua, va, wa);
}
Dij(n);
if(ener/h[1]>1000000){
cout<<2002000;
return 0;
} // 特判hack数据
Astar(ener/h[1]); // 最大方案数不能超过 总能量/最短路
printf("%d", ans);
return 0;
}