您的位置:首页 > 其它

poj3259 Wormholes(floyd||spfa判断负环)

2016-05-31 21:05 483 查看
http://poj.org/problem?id=3259

题意:n个点,m个正权边,w个负权边,正权边为双向,负权边为单向,判断是否有负环。

思路:首先知道何为负环,例如有3个点编号1,2,3,任意两点之间都存在一条边,那么1,2,3存在一个环,其上权值和为负即为负环。floyd和spfa两种做法,floyd法卡的时间紧,不但要把min改成普通判断,输出也不能在函数内。整体来说floyd太容易超时了,判环条件就是判断对角线上的点,如果有负值,说明松弛过程中又回到了原来的点且更新比0小。spfa的判环条件就是某个点进入队列的次数超过n次,则存在负环(spfa无法处理带负环的图)。而dijkstra无法判断。

#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>

using namespace std;

typedef long long LL;

const int N = 600;
const int INF = 0x3f3f3f3f;

int G

, dis
, num
, n, s;
bool vis
;

int floyd()
{
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
// G[i][j] = min(G[i][j], G[i][k]+G[k][j]);
if(G[i][k]+G[k][j] < G[i][j])
G[i][j] = G[i][k]+G[k][j];
}
if(G[i][i] < 0) return 1;
}
return 0;
}

int spfa()
{
queue<int>que;
for(int i = 1; i <= n; i++)
{
dis[i] = INF;
num[i] = 0;
}
dis[1] = 0;
vis[1] = true;
que.push(1);
while(!que.empty())
{
int now = que.front();
que.pop();
vis[now] = false;//记得还原!!
for(int i = 1; i <= n; i++)
{
if(dis[now]+G[now][i]<dis[i])
{
dis[i] = dis[now]+G[now][i];
if(!vis[i])
{
vis[i] = true;
num[i]++;
if(num[i] > n) return 1;
que.push(i);
}
}
}
}
return 0;
}

int main()
{
// freopen("in.txt", "r", stdin);
int f, m, e, w, t;
scanf("%d", &f);
while(f--)
{
scanf("%d%d%d", &n, &m, &w);
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(i == j) G[i][j] = 0;
else G[i][j] = INF;
}
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &s, &e, &t);
if(t < G[s][e]) G[s][e] = G[e][s] = t;
}
for(int i = 1; i <= w; i++)
{
scanf("%d%d%d", &s, &e, &t);
G[s][e] = -t;
}
int ans = floyd();
// int ans = spfa();
if(ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj