John 在他的農場中閒逛時發現了許多蟲洞。蟲洞能夠看做一條十分奇特的有向邊,並可使你返回到過去的一個時刻(相對你進入蟲洞以前)。John 的每一個農場有 M條小路(無向邊)鏈接着 N從 1到 N標號)塊地,並有 W個蟲洞。如今 John 想借助這些蟲洞來回到過去(在出發時刻以前回到出發點),請你告訴他能辦到嗎。 John 將向你提供F 個農場的地圖。沒有小路會耗費你超過 10^4 的時間,固然也沒有蟲洞回幫你回到超過 10^4秒之前。ios
第一行一個整數F表示農場個數;對於每一個農場:第一行,三個整數 N,M,W;接下來 M行,每行三個數 S,E,T 表示在標號爲 S的地與標號爲 E的地中間有一條用時 T秒的小路;接下來 W行,每行三個數 S,E,T 表示在標號爲 S的地與標號爲 E的地中間有一條可使 John 到達 T秒前的蟲洞。數組
輸出共 F行,若是 John 能在第 I個農場實現他的目標,就在第 I行輸出 YES,不然輸出 NO。測試
對於所有數據:
1<=F<=5
1<=N<=500
1<=M<=2500
1<=W<=200
1<=S,E<=N
|T|<=10^4spa
迷人吶。code
這道題一看其實就有思路了,由於他給咱們一些富有魅力的詞彙:「有向邊」 「有M條小路(無向邊)」。因而咱們不難想到最短路求解。
我一開始想要的是dijkstra,緣由是被樣例給迷惑了,其實他並無說蟲洞是從哪到哪,而樣例都是從終點到第一個點。隊列
咱們不難看出路是雙向的,而蟲洞只有單向且權值爲負。題目中:「如今 John 想借助這些蟲洞來回到過去(在出發時刻以前回到出發點)」的意義就是說若是一號點到一號點的最短路爲負,那麼輸出YES。而後剛看題意時我還很懵(´・ω・`)(不知道農場是啥),後來才發現一個農場至關於一組測試數據。string
比賽交了兩次,而後竟沒AC——第一次visit數組(v數組,記錄是否在隊列中)過小,我把它開大了。而後75分,俺含着淚看了代碼,鏈式前向星開小了(雙向邊×2)(┳_┳)...。it
好了,裸的負迴路SPFA。
上代碼:io
#include <cstdio> #include <iostream> #include <cstring> #include <queue> using namespace std; int n,m,w; struct edge{ int x;//起點 int y;//終點 int val;//權值 int last;//以x爲起點的上一條路在e(鏈式前向星)中的位置 }e[6000]; int head[2000];//head[i]表示以i爲起點的最後一條路在e中的位置 int cnt;//道路數量 int dis[2000];//記錄最短路 int v[2000];//是否在隊列中 queue<int> q;//隊列 void add(int a, int b, int v)//記錄道路和蟲洞(鏈式前向星) { ++cnt; e[cnt].x = a; e[cnt].y = b; e[cnt].val = v; e[cnt].last = head[a]; head[a] = cnt; } void spfa() { memset(dis,0x3f3f3f3f,sizeof(dis)); memset(v,0,sizeof(v)); dis[1] = 0; q.push(1);//1進隊列 v[1] = 1; while(!q.empty()) { if(dis[1] < 0) return; int r = q.front(); for(int i = head[r]; i != 0; i = e[i].last) { int k = e[i].y; if(dis[r] + e[i].val < dis[k]) { dis[k] = dis[r] + e[i].val; if(v[k] == 0)//當k不在隊列中(差點忘記呀) { q.push(k); v[k] = 1; } } } q.pop(); v[r] = 0; } } int main() { int t; scanf("%d", &t); while(t--) { cnt = 0; memset(e,0,sizeof(e)); memset(head,0,sizeof(head)); scanf("%d%d%d", &n, &m, &w); for(int i = 1; i <= m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, c); add(b, a, c); } for(int i = 1; i <= w; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, -c);//只記錄一次 } spfa(); // for(int i = 1; i <= n; i++)//測試不用管 // printf("%d\n",dis[i]);//測試不用管 + 1 if(dis[1] < 0) printf("YES"); else printf("NO"); printf("\n"); } return 0; }