洛谷P4880 抓住czxnode
這道題說來都心酸,在第一次獲得\(T=0\)的\(30pt\)s後,開始肝正解c++
可是在判斷的時候忽略了一種狀況(我並無意識到),一直卡在了\(90pts\),甚至還發了貼去求助(然而並無人回我QAQ)spa
後來在同桌的幫助下,意識到了缺乏一種狀況,而後本身想出了這種狀況怎麼處理,可是.....由於手賤多寫了一個「\(=\)」,又在#1和#2反覆橫跳(我真慘菜).net
最後耐心地又敲了一遍,才艱難的A掉了這道並不難的藍題code
好了,吐槽完了,開始正題吧blog
只要會求最短路的,應該都沒問題吧,\(30pts\)給得死死的排序
多說一點:\(T=0\)意味着\(czx\)不會瞬移,則\(czx\)一直在\(e\)這個位置,那抓住他的最短期天然就是從\(b\)到\(e\)的最短路長度咯get
在除\(T=0\)的特殊狀況外,也會存在一種狀況不用考慮瞬移:咱們在\(czx\)第一次瞬移以前就抓住了他,即從\(b\)到\(e\)的最短路長度\(<\)第一次瞬移的時間it
注意一下,這裏的「第一次」並非指輸入的第一組瞬移數據,而是排序後的第一次(即咱們將全部瞬移按照時間節點從早到晚排序後的第一次瞬移)io
以後的狀況就都是須要考慮瞬移的了(咱們用\(dis[i]\)表示從\(1\)到\(i\)的最短期)
設\(czx\)第\(i\)次瞬移到的點爲\(pi\)、時間爲\(ti\)
這裏可能你們會疑惑:爲何是「\(≤\)」而不是「\(<\)」?題目中不是說在一個瞬移時間點,老是\(czx\)先瞬移走,而後咱們纔到,這樣是抓不住的啊
題目中確實說明了這一點,可是這個規則並不影響咱們的這個判斷,而是影響咱們下面的另外一個判斷(下面會着重點出)
而後,咱們再來解釋一下這個判斷的原理(也能解釋上面的疑惑):
若咱們比\(czx\)先到達\(pi\)這個點(對應\(dis[pi]\)\(<\)\(ti\)),那咱們就在\(pi\)這個點等着抓他就行了(守株待兔嘛)
若咱們和\(czx\)同時到達\(pi\)這個點(對應\(dis[pi]\)\(=\)\(ti\)),那咱們就正好抓住他
(這就是我一直忽略的狀況,下面給出圖來幫助理解)
在第\(2\)時刻,\(czx\)已經到達點\(3\),而咱們還在從\(1\)到\(3\)的路上,那顯然是\(dis[pi]>ti\)的狀況
可是在第\(3\)時刻咱們到達了\(czx\)所在的點\(3\),而此時\(czx\)尚未進行下一次的瞬移,因此咱們抓住了他
面對上面這種狀況,咱們單單由於\(dis[pi]>ti\)的話,就會錯失掉在第\(3\)時刻抓住\(czx\)的機會!因此咱們還須要加個判斷防止誤判:\(dis[a[i].p]<a[i+1].t\)
仍是來解釋一下原理:若是咱們到達\(pi\)這個點的時間在\(czx\)下一次瞬移以前,那咱們依舊可以抓住他,因此這種狀況答案就是咱們到達\(pi\)的時間
再着重講一下爲何這裏就是「\(<\)」而不是「\(≤\)」,正如上面的疑惑,題目中說定了在一個瞬移的時間點,老是\(czx\)先瞬移而後咱們再到達。因此當咱們到達\(pi\)時,\(czx\)已經瞬移走了,故咱們抓不住他(請你們注意區分qwq)
#include <bits/stdc++.h> using namespace std; priority_queue<pair<int,int> > q; int n,m,t,b,E,x,y,z; int tot,dis[1000010],vis[1000010],head[1000010]; struct node { int to,net,val; } e[1000010]; struct nodes { int t,p; } a[1000010]; inline void add(int u,int v,int w) { e[++tot].to=v; e[tot].val=w; e[tot].net=head[u]; head[u]=tot; } inline void dijkstra(int s) { //Dijkstra求最短路板子 for(register int i=1;i<=n;i++) { vis[i]=0; dis[i]=2005020600; } dis[s]=0; q.push(make_pair(0,s)); while(!q.empty()) { int x=q.top().second; q.pop(); if(vis[x]) continue; vis[x]=1; for(register int i=head[x];i;i=e[i].net) { int v=e[i].to; if(dis[v]>dis[x]+e[i].val) { dis[v]=dis[x]+e[i].val; q.push(make_pair(-dis[v],v)); } } } } inline bool cmp(nodes x,nodes y) { return x.t<y.t; } int main() { scanf("%d%d%d%d",&n,&m,&b,&E); for(register int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } scanf("%d",&t); for(register int i=1;i<=t;i++) { scanf("%d%d",&a[i].t,&a[i].p); } sort(a+1,a+1+t,cmp); //將全部瞬移按照時間點從早到晚排序 dijkstra(b); if(dis[E]<a[1].t||t==0) { //不用管瞬移的兩種狀況 printf("%d",dis[E]); return 0; } for(register int i=1;i<=t;i++) { //枚舉瞬移找答案 if(dis[a[i].p]<=a[i].t) { //守株待兔或正好抓住的狀況 printf("%d",a[i].t); return 0; } else { if(dis[a[i].p]<a[i+1].t) { //在下一次瞬移前抓住的狀況 printf("%d",dis[a[i].p]); return 0; } } } return 0; }
最後,若是有任何地方不懂或不對的,歡迎你們在評論區留言,我會及時回覆,謝謝你們啊qwq