題目描述 尋找一個從頂點1所能到達的負環,負環定義為:一個邊權之和為負的環。 輸入格式 第一行一個正整數T表示數據組數,對於每組數據: 第一行兩個正整數N M,表示圖有N個頂點,M條邊 接下來M行,每行三個整數a b w,表示a b有一條權值為w的邊( 若w using namespace std; ...
題目描述
尋找一個從頂點1所能到達的負環,負環定義為:一個邊權之和為負的環。
輸入格式
第一行一個正整數T表示數據組數,對於每組數據:
第一行兩個正整數N M,表示圖有N個頂點,M條邊
接下來M行,每行三個整數a b w,表示a->b有一條權值為w的邊(若w<0則為單向,否則雙向)
輸出格式
共T行。對於每組數據,存在負環則輸出一行"YE5"(不含引號),否則輸出一行"N0"(不含引號)。
樣例輸入
2
3 4
1 2 2
1 3 4
2 3 1
3 1 -3
3 3
1 2 3
2 3 4
3 1 -8
樣例輸出
N0
YE5
數據範圍和提示
$$
n\leqslant2000
m\leqslant 3000
-10000\leqslant w\leqslant 10000
T\leqslant 10
$$
建議複製輸出格式中的字元串。 本題數據感謝@negiizhao的精心構造,請不要使用玄學演算法。本題數據有更新
思路
作為一道模板題也沒什麼好說的。。不過坑有以下幾點:
- 只能用朴素spfa,而不能加優化qwq。新的數據卡了spfa優化。所以:正權圖用dijkstra,負權圖用朴素spfa,spfa優化在負權圖上往往是負優化。
- 那幾個字元串,YE5後面是5不是S,N0後面是0不是N。。。
實現和代碼
和朴素spfa沒有太大區別,只是每個點的入隊次數最多\(n-1\)次(如果是\(n\)次,就直接返回有負環)
代碼如下:
#include<bits/stdc++.h>
using namespace std;
int T,n,m,vis[2005],dis[2005];
vector<int>v[2005],val[2005];
queue<int>q;
bool spfa(int s)
{
while(!q.empty()) q.pop();
memset(dis,0x3f3f3f3f,sizeof(dis));
dis[1]=0;
q.push(1);
while(!q.empty())
{
int f=q.front();q.pop();int sz=v[f].size();
for(int i=0;i<sz;i++)
{
int e=v[f][i];
if(dis[f]+val[f][i]<dis[e])
{
vis[e]++;
if(vis[e]<n)
{
q.push(e);
dis[e]=dis[f]+val[f][i];
}
else
{
return true;
}
}
}
}
return false;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=n;i++) val[i].clear();
memset(vis,0,sizeof(vis));
vis[1]=1;
for(int i=1;i<=m;i++)
{
int aa,bb,ww;
scanf("%d %d %d",&aa,&bb,&ww);
if(ww<0) v[aa].push_back(bb),val[aa].push_back(ww);
else
{
v[aa].push_back(bb);
v[bb].push_back(aa);
val[aa].push_back(ww);
val[bb].push_back(ww);
}
}
if(spfa(1)) printf("YE5\n");
else printf("N0\n");
}
return 0;
}