描述

输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 
要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一个点沿着某条路径出发, 又回到了自己, 而且所经过的边上的权和小于0, 就说这条路是一个负权回路.
如果存在负权回路, 只输出一行-1;
如果不存在负权回路, 再求出一个点S(1 <= S <= N)到每个点的最短路的长度. 约定: S到S的距离为0, 如果S与这个点不连通, 则输出NoPath.

格式

输入格式

第一行: 点数N(2 <= N <= 1,000), 边数M(M <= 100,000), 源点S(1 <= S <= N);
以下M行, 每行三个整数a, b, c表示点a, b(1 <= a, b <= N)之间连有一条边, 权值为c(-1,000,000 <= c <= 1,000,000)

输出格式

如果存在负权环, 只输出一行-1, 否则按以下格式输出
共N行, 第i行描述S点到点i的最短路: 
如果S与i不连通, 输出NoPath;
如果i = S, 输出0;
其他情况输出S到i的最短路的长度.

输入
6 8 1
1 3 4
1 2 6
3 4 -7
6 4 2
2 4 5
3 6 3
4 5 1
3 5 4
输出
0
6
4
-3
-2
7
思路:spfa算法,不过这道题存在陷阱。第一存在重边,解决方法用邻接矩阵表示图,保留权值最小的一个。第二图可能不连通,解决方法对每个结点进行spfa,为了优化时间,设置一个used数组标志已经遍历过的结点,遍历过的结点无需再进行spfa。最后加上若d[s]<0则存在负环。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=;
const int INF=0x7f7f7f7f;
int n,m,s;
int contain;
int mp[MAXN][MAXN];
int d[MAXN];
int cnt[MAXN];
bool vis[MAXN],used[MAXN];
void addedge(int u,int v,int w)
{
if(mp[u][v]>w)
mp[u][v]=w;
} bool spfa(int scource)
{
for(int i=;i<=n;i++)
{
d[i]=INF;
vis[i]=false;
} queue<int> que;
que.push(scource);
vis[scource]=true;
used[scource]=true;
d[scource]=;
while(!que.empty())
{
int now = que.front();que.pop();
vis[now]=false;
for(int i=;i<=n;i++)
{
if(now==i||mp[now][i]==INF) continue;
if(d[i]>d[now]+mp[now][i])
{
d[i]=d[now]+mp[now][i];
if(d[scource]<) return true;
if(!vis[i])
{
used[i]=vis[i]=true;
que.push(i);
cnt[i]++;
if(cnt[i]>=n) return true;
}
} }
}
return false;
} void solve()
{
for(int i=;i<=n;i++)
{
if(!used[i]&&spfa(i))
{
printf("-1\n");
return ;
}
}
if(spfa(s))
{
printf("-1\n");
}
else
{
for(int i=;i<=n;i++)
if(d[i]==INF) printf("NoPath\n");
else printf("%d\n",d[i]);
}
} int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
if(i==j) mp[i][j]=;
else mp[i][j]=mp[j][i]=INF;
for(int i=;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
solve(); return ;
}

spfa+前向星可解决重边问题。d[source][source]<0则存在负环

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN=;
const int INF=0x3f3f3f3f;
struct Edge{
int to,w,next;
}es[];
int head[MAXN],tot;
int n,m,source;
int d[MAXN][MAXN],vis[MAXN],used[MAXN];
void addedge(int u,int v,int w)
{
es[tot].to=v;
es[tot].w=w;
es[tot].next=head[u];
head[u]=tot++;
}
bool spfa(int s)
{
for(int i=;i<=n;i++)
{
d[s][i]=INF;
vis[i]=;
}
queue<int> que;
que.push(s);
d[s][s]=;
vis[s]=;
used[s]=;
while(!que.empty())
{
int u=que.front();que.pop();
vis[u]=;
for(int i=head[u];i!=-;i=es[i].next)
{
Edge e=es[i];
if(d[s][e.to]>d[s][u]+e.w)
{
d[s][e.to]=d[s][u]+e.w;
if(d[s][s]<) return true;
if(!vis[e.to])
{
que.push(e.to);
vis[e.to]=;
used[e.to]=;
}
}
}
}
return false;
}
void solve()
{
if(spfa(source))
{
printf("-1\n");
return ;
}
for(int i=;i<=n;i++)
{
if(!used[i]&&spfa(i))
{
printf("-1\n");
return ;
}
}
for(int i=;i<=n;i++)
{
if(d[source][i]==INF) printf("NoPath\n");
else printf("%d\n",d[source][i]);
}
}
int main()
{
memset(head,-,sizeof(head));
scanf("%d%d%d",&n,&m,&source);
for(int i=;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
solve(); return ;
}

vijos:P1053Easy sssp(spfa判环)的更多相关文章

  1. 2018.09.09 poj2949Word Rings(01分数规划+spfa判环)

    传送门 这题要先巧妙的转化一下. 对于每个字符串,我们把头尾的两个小字符串对应的点连边,边权是这个字符串的长度. 这样最多会出现26*26个点. 这个时候就只用求出边权和跟边数的最大比值了. 这个显然 ...

  2. POJ 1860 Currency Exchange【SPFA判环】

    Several currency exchange points are working in our city. Let us suppose that each point specializes ...

  3. 【BZOJ 3232】圈地游戏 二分+SPFA判环/最小割经典模型

    最小割经典模型指的是“一堆元素进行选取,对于某个元素的取舍有代价或价值,对于某些对元素,选取后会有额外代价或价值”的经典最小割模型,建立倒三角进行最小割.这个二分是显然的,一开始我也是想到了最小割的那 ...

  4. POJ 2240 Arbitrage (spfa判环)

    Arbitrage Arbitrage is the use of discrepancies in currency exchange rates to transform one unit of ...

  5. 2018.09.12 poj3621Sightseeing Cows(01分数规划+spfa判环)

    传送门 01分数规划板题啊. 发现就是一个最优比率环. 这个直接二分+spfa判负环就行了. 代码: #include<iostream> #include<cstdio> # ...

  6. Vijos1053 Easy sssp[spfa 负环]

    描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一 ...

  7. POJ 3259 Wormholes(SPFA判负环)

    题目链接:http://poj.org/problem?id=3259 题目大意是给你n个点,m条双向边,w条负权单向边.问你是否有负环(虫洞). 这个就是spfa判负环的模版题,中间的cnt数组就是 ...

  8. Poj 3259 Wormholes(spfa判负环)

    Wormholes Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 42366 Accepted: 15560 传送门 Descr ...

  9. poj1860(spfa判正环)

    题目连接:http://poj.org/problem?id=1860 题意:有多种从a到b的汇率,在你汇钱的过程中还需要支付手续费,那么你所得的钱是 money=(nowmoney-手续费)*rat ...

随机推荐

  1. Ejabberd作为推送服务的优化手段(转)

    AVOS Cloud目前还在用Ejabberd做Android的消息推送服务.当时选择Ejabberd,是因为Ejabberd是一个发展很长时间的XMPP实现,并且基于Erlang,设想能在我们自主研 ...

  2. IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(二)

    IdentityServer4 + SignalR Core +RabbitMQ 构建web即时通讯(二) IdentityServer4 用户中心生成数据库 上文已经创建了所有的数据库上下文迁移代码 ...

  3. js异步请求发展史和yield

    万恶的回调 对前端工程师来说,异步回调是再熟悉不过了,浏览器中的各种交互逻辑都是通过事件回调实现的,前端逻辑越来越复杂,导致回调函数越来越多,同时 nodejs 的流行也让 javascript 在后 ...

  4. SQL ROW_NUMBER() 分页使用示例

    ALTER PROC [dbo].[TestProPage] , AS BEGIN SELECT * FROM (SELECT *,ROW_NUMBER() OVER(ORDER BY IndexID ...

  5. EntityFramework走马观花之CRUD(中)

    如果是独立的实体对象,在底层数据库中它对应一张独立的表,那么,对它进行新建.删除和修改没有任何难度,实在不值浪费笔墨在它上头. 在现实项目中,完全独立的对象少之又少,绝大多数情况都是对象之间有着紧密的 ...

  6. cf-341C Iahub and Permutations

    C. Iahub and Permutations time limit per test 1 second memory limit per test 256 megabytes input sta ...

  7. Python 字符串操作(截取/替换/查找/分割)

    Python 截取字符串使用 变量[头下标:尾下标],就可以截取相应的字符串,其中下标是从0开始算起,可以是正数或负数,下标可以为空表示取到头或尾. # 例1:字符串截取 str = '1234567 ...

  8. Entity Framework 4.1:多对多的关系

    这篇文章讨论多对多的关系. 让我们从最简单的例子开始.我们让 EF4.1 来推断表的映射.我在订单和雇员之间建模多对多的关系. )] publicstring CustomerName { get; ...

  9. Cocos2d-js官方完整项目教程翻译:六、添加Chipmunk物理引擎在我们的游戏世界里

    添加Chipmunk物理引擎在我们的游戏世界里         一.简介                   cocos2d JS能给我们力量来创造令人印象深刻的游戏世界.但缺乏某种现实.       ...

  10. 中文WebFont探索

    本文主要讲中文webFont的相关知识,包含了业界现状.WebFont优势.实现方案等. 一 业界使用WebFont现状 1.1 英文WebFont使用现状 英文版已使用非常广泛.比较有名的字体库:G ...