[毒瘤][A*][SDOI2010] 魔法豬學院
阿新 • • 發佈:2020-07-20
先把程式碼放這, 解釋下次再說
其實讓我很不解明明是個 \(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; } 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 為預估 // 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; }