POJ 3259 Wormholes 【Floyd判斷負環】
題目大意:
FJ 有 N 塊田野【編號 1…n】田野間有 M 條路【雙向】
同時有 W 個蟲洞,通過這個蟲洞到達另一個田野,可以回到一段時間以前【單向】
問:FJ 是否能在田地中遇到以前的自己
具體思路:
雙向路爲正權,單向路爲負權,判斷圖中是否存在負環,存在則可以遇到以前的自己,至於爲什麼上一篇博客有解釋
可用spfa求解,但是spfa是針對單源點的,此題沒有指定源點,因此無法ac
至於那些默認1號田野爲出發點的能ac可能是因爲題目給的測試數據是連通圖
因此本題更適合用floyd判斷負權(下方我也貼出spfa以1號爲出發點的代碼)
初始化到自身的時間爲0到其它田野的時間爲無窮,若存在負環,最終到自身的時間會被松馳爲負值,(可以遇到以前的自己)
具體代碼:
//floyd
#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 505;
const int INF = 1e9;
int maps[N][N];
int F, n, m, w;
void init()
{
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i == j) maps[i][j] = 0; //初始化到自身的時間爲0
else maps[i][j] = INF; //到其它田野的時間爲無窮大
}
bool floyd()
{
for(int k=1;k<=n;k++)
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
if (maps[i][j] > maps[i][k] + maps[k][j])
maps[i][j] = maps[i][k] + maps[k][j];
if (maps[i][i] < 0)return true;
}
return false;
}
int main()
{
cin >> F;
while (F--)
{
cin >> n >> m >> w;
init();
for (int i = 1; i <= m + w; i++)
{
int x, y, t;
cin >> x >> y >> t;
if (i <= m )
{
if(t < maps[x][y])//考慮重邊
maps[x][y] = maps[y][x] = t;
}
else maps[x][y] = -t; //蟲洞是單向的,其實我絕對這裏也應該考慮重邊,但是沒有也能ac
}
if (floyd())printf("YES\n");
else printf("NO\n");
}
return 0;
}
順便貼出spfa的做法(1號爲出發點)
//spfa
#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 505;
const int INF = 1e9;
struct Node {
int x, y, t; //x->y這條路/蟲洞耗時t
Node(int x, int y, int t) { this->x = x, this->y = y, this->t = t; }
};
vector<Node> maps[N];
int visit[N]; //記錄是否在隊列中
int index[N]; //記錄入隊次數
int d[N]; //d[i]表示穿梭到田野i的時間
int F, n, m, w;
int flag = 0;
void spfa()
{
for (int i = 1; i <= n; i++)
visit[i] = 0, index[i] = 0, d[i] = INF;
visit[1] = 1;
index[1] = 1;
d[1] = 0;
queue<int> q;
q.push(1);
while (q.size())
{
int t = q.front();
q.pop();
visit[t] = 0;
for (vector<Node>::iterator it = maps[t].begin(); it != maps[t].end(); it++)
{
if (d[it->y] > d[t] + it->t) {
d[it->y] = d[t] + it->t;
if (!visit[it->y]) {
visit[it->y] = 1;
q.push(it->y);
index[it->y]++;
if (index[it->y] > n) {
flag = 1;
return;
}
}
}
}
}
}
int main()
{
//freopen("C:\\Users\\Tsai\\Desktop\\in.txt", "r", stdin);
cin >> F;
while (F--)
{
cin >> n >> m >> w;
for (int i = 1; i <= m + w; i++)
{
int x, y, t;
cin >> x >> y >> t;
if (i <= m) {
maps[x].push_back(Node(x, y, t)); //路是雙向的
maps[y].push_back(Node(y, x, t));
}
else maps[x].push_back(Node(x, y, -t)); //蟲洞是單向的
}
spfa();
if (flag)printf("YES\n");
else printf("NO\n");
for (int i = 1; i <= n; i++)
maps[i].clear();
flag = 0;
}
return 0;
}