抓住czx

抓住czx

洛谷P4880 抓住czxnode

前言(吐槽 珂忽略)

這道題說來都心酸,在第一次獲得\(T=0\)\(30pt\)s後,開始肝正解c++

可是在判斷的時候忽略了一種狀況(我並無意識到),一直卡在了\(90pts\),甚至還發了貼去求助(然而並無人回我QAQ)spa

後來在同桌的幫助下,意識到了缺乏一種狀況,而後本身想出了這種狀況怎麼處理,可是.....由於手賤多寫了一個「\(=\)」,又在#1和#2反覆橫跳(我真慘.net

最後耐心地又敲了一遍,才艱難的A掉了這道並不難的藍題code


解題思路

好了,吐槽完了,開始正題吧blog

  • \(T=0\)的特殊狀況

只要會求最短路的,應該都沒問題吧,\(30pts\)給得死死的排序

多說一點:\(T=0\)意味着\(czx\)不會瞬移,則\(czx\)一直在\(e\)這個位置,那抓住他的最短期天然就是從\(b\)\(e\)的最短路長度咯get

  • 完整正解

在除\(T=0\)的特殊狀況外,也會存在一種狀況不用考慮瞬移:咱們在\(czx\)第一次瞬移以前就抓住了他,即從\(b\)\(e\)的最短路長度\(<\)第一次瞬移的時間it

注意一下,這裏的「第一次」並非指輸入的第一組瞬移數據,而是排序後的第一次(即咱們將全部瞬移按照時間節點從早到晚排序後的第一次瞬移)io

以後的狀況就都是須要考慮瞬移的了(咱們\(dis[i]\)表示從\(1\)\(i\)的最短期

\(czx\)\(i\)次瞬移到的點爲\(pi\)、時間爲\(ti\)

  • \(dis[pi]≤ti\),說明咱們在第\(i\)次瞬移後抓住了他

這裏可能你們會疑惑:爲何是「\(≤\)」而不是「\(<\)」?題目中不是說在一個瞬移時間點,老是\(czx\)先瞬移走,而後咱們纔到,這樣是抓不住的啊

題目中確實說明了這一點,可是這個規則並不影響咱們的這個判斷,而是影響咱們下面的另外一個判斷(下面會着重點出)

而後,咱們再來解釋一下這個判斷的原理(也能解釋上面的疑惑):

  1. 若咱們比\(czx\)先到達\(pi\)這個點(對應\(dis[pi]\)\(<\)\(ti\)),那咱們就在\(pi\)這個點等着抓他就行了(守株待兔嘛)

  2. 若咱們和\(czx\)同時到達\(pi\)這個點(對應\(dis[pi]\)\(=\)\(ti\)),那咱們就正好抓住

  • \(dis[pi]>ti\),說明咱們沒法在\(pi\)這個點抓住\(czx\),可是也須要加以討論

(這就是我一直忽略的狀況,下面給出圖來幫助理解)

在第\(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)


代碼Code

#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

相關文章
相關標籤/搜索