poj 3259 Bellman-ford + SPFA
2016-08-02 11:35
260 查看
Wormholes
Description
While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ's farms
comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..N, M (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.
As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .
To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000
seconds.
Input
Line 1: A single integer, F. F farm descriptions follow.
Line 1 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2..M+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected
by more than one path.
Lines M+2..M+W+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.
Output
Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).
Sample Input
Sample Output
Hint
For farm 1, FJ cannot travel back in time.
For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.
题意:
虫洞问题,现在有n个点,m条边,代表现在可以走的通路,比如从a到b和从b到a需要花费c时间
现在在地上出现了w个虫洞,虫洞的意义就是你从a到b话费的时间是-c(时间倒流,并且虫洞是单向的)
现在问你从某个点开始走,能回到从前
Bellman-ford
SPFA
建立一个队列,初始时队列里只有起始点,再建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点作为起始点去刷新到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。
判断有无负环:
如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)
首先建立起始点a到其余各点的
最短路径表格
首先源点a入队,当队列非空时:
1、队首元素(a)出队,对以a为起始点的所有边的终点依次进行松弛操作(此处有b,c,d三个点),此时路径表格状态为:
在松弛时三个点的最短路径估值变小了,而这些点队列中都没有出现,这些点
需要入队,此时,队列中新入队了三个结点b,c,d
队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e点),此时路径表格状态为:
在最短路径表中,e的最短路径估值也变小了,e在队列中不存在,因此e也要
入队,此时队列中的元素为c,d,e
队首元素c点出队,对以c为起始点的所有边的终点依次进行松弛操作(此处有e,f两个点),此时路径表格状态为:
在最短路径表中,e,f的最短路径估值变小了,e在队列中存在,f不存在。因此
e不用入队了,f要入队,此时队列中的元素为d,e,f
队首元素d点出队,对以d为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:
在最短路径表中,g的最短路径估值没有变小(松弛不成功),没有新结点入队,队列中元素为f,g
队首元素f点出队,对以f为起始点的所有边的终点依次进行松弛操作(此处有d,e,g三个点),此时路径表格状态为:
在最短路径表中,e,g的最短路径估值又变小,队列中无e点,e入队,队列中存在g这个点,g不用入队,此时队列中元素为g,e
队首元素g点出队,对以g为起始点的所有边的终点依次进行松弛操作(此处只有b点),此时路径表格状态为:
在最短路径表中,b的最短路径估值又变小,队列中无b点,b入队,此时队列中元素为e,b
队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:
在最短路径表中,g的最短路径估值没变化(松弛不成功),此时队列中元素为b
队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e这个点),此时路径表格状态为:
在最短路径表中,e的最短路径估值没变化(松弛不成功),此时队列为空了
最终a到g的最短路径为14
#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 10005
int map[MAXN][MAXN];
int dis[MAXN];
int num[MAXN],vis[MAXN];
int n,m,w;
bool SPFA()
{
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
dis[i]=INF;
queue<int>q;
dis[0]=0; vis[0]=1;
q.push(0); num[0]++;
while(q.size())
{
int p=q.front();
q.pop();
vis[p]=0;
for(int i=1;i<=n;i++){
if(dis[p]+map[p][i]<dis[i]){
dis[i]=dis[p]+map[p][i];
if(vis[i]==0){
vis[i]=1;
num[i]++;
q.push(i);
if(num[i]>n)
return true;
}
}
}
}
return false;
}
int main()
{
int T;
//freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
map[i][j]=map[j][i]=INF;
int a,b,c;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
if(c<map[a][b])
map[a][b]=map[b][a]=c;
}
for(int i=1;i<=w;i++){
scanf("%d%d%d",&a,&b,&c);
map[a][b]=-c;
}
for(int i=1;i<=n;i++)
map[0][i]=0;
if(SPFA())
puts("YES");
else
puts("NO");
}
return 0;
}
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 43809 | Accepted: 16085 |
While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ's farms
comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..N, M (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.
As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .
To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000
seconds.
Input
Line 1: A single integer, F. F farm descriptions follow.
Line 1 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2..M+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected
by more than one path.
Lines M+2..M+W+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.
Output
Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).
Sample Input
2 3 3 1 1 2 2 1 3 4 2 3 1 3 1 3 3 2 1 1 2 3 2 3 4 3 1 8
Sample Output
NO YES
Hint
For farm 1, FJ cannot travel back in time.
For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.
题意:
虫洞问题,现在有n个点,m条边,代表现在可以走的通路,比如从a到b和从b到a需要花费c时间
现在在地上出现了w个虫洞,虫洞的意义就是你从a到b话费的时间是-c(时间倒流,并且虫洞是单向的)
现在问你从某个点开始走,能回到从前
Bellman-ford
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INF 0x3f3f3f3f int top; struct node { int u,v,t; }path[6010]; int n,m,w; void add(int u,int v,int t) { path[top].u=u; path[top].v=v; path[top++].t=t; } int bellman_ford(int n) { int weight[520]; for(int i=0;i<=n;i++) weight[i]=INF; weight[1]=0; int u,v,t; for(int i=0;i<n-1;i++){ for(int j=0;j<top;j++){ u=path[j].u; v=path[j].v; t=path[j].t; if(weight[u]+t<weight[v]) weight[v]=weight[u]+t; } } for(int j=0;j<top;j++){ u=path[j].u; v=path[j].v; t=path[j].t; if(weight[u]+t<weight[v]) return 0; } return 1; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&w); top=0; int u,v,t; for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&t); add(u,v,t); add(v,u,t); } for(int i=0;i<w;i++){ scanf("%d%d%d",&u,&v,&t); add(u,v,-t); } if(!bellman_ford(n)) printf("YES\n"); else printf("NO\n"); } return 0; }
SPFA
建立一个队列,初始时队列里只有起始点,再建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点作为起始点去刷新到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。
判断有无负环:
如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)
首先建立起始点a到其余各点的
最短路径表格
首先源点a入队,当队列非空时:
1、队首元素(a)出队,对以a为起始点的所有边的终点依次进行松弛操作(此处有b,c,d三个点),此时路径表格状态为:
在松弛时三个点的最短路径估值变小了,而这些点队列中都没有出现,这些点
需要入队,此时,队列中新入队了三个结点b,c,d
队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e点),此时路径表格状态为:
在最短路径表中,e的最短路径估值也变小了,e在队列中不存在,因此e也要
入队,此时队列中的元素为c,d,e
队首元素c点出队,对以c为起始点的所有边的终点依次进行松弛操作(此处有e,f两个点),此时路径表格状态为:
在最短路径表中,e,f的最短路径估值变小了,e在队列中存在,f不存在。因此
e不用入队了,f要入队,此时队列中的元素为d,e,f
队首元素d点出队,对以d为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:
在最短路径表中,g的最短路径估值没有变小(松弛不成功),没有新结点入队,队列中元素为f,g
队首元素f点出队,对以f为起始点的所有边的终点依次进行松弛操作(此处有d,e,g三个点),此时路径表格状态为:
在最短路径表中,e,g的最短路径估值又变小,队列中无e点,e入队,队列中存在g这个点,g不用入队,此时队列中元素为g,e
队首元素g点出队,对以g为起始点的所有边的终点依次进行松弛操作(此处只有b点),此时路径表格状态为:
在最短路径表中,b的最短路径估值又变小,队列中无b点,b入队,此时队列中元素为e,b
队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:
在最短路径表中,g的最短路径估值没变化(松弛不成功),此时队列中元素为b
队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e这个点),此时路径表格状态为:
在最短路径表中,e的最短路径估值没变化(松弛不成功),此时队列为空了
最终a到g的最短路径为14
#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 10005
int map[MAXN][MAXN];
int dis[MAXN];
int num[MAXN],vis[MAXN];
int n,m,w;
bool SPFA()
{
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
dis[i]=INF;
queue<int>q;
dis[0]=0; vis[0]=1;
q.push(0); num[0]++;
while(q.size())
{
int p=q.front();
q.pop();
vis[p]=0;
for(int i=1;i<=n;i++){
if(dis[p]+map[p][i]<dis[i]){
dis[i]=dis[p]+map[p][i];
if(vis[i]==0){
vis[i]=1;
num[i]++;
q.push(i);
if(num[i]>n)
return true;
}
}
}
}
return false;
}
int main()
{
int T;
//freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
map[i][j]=map[j][i]=INF;
int a,b,c;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
if(c<map[a][b])
map[a][b]=map[b][a]=c;
}
for(int i=1;i<=w;i++){
scanf("%d%d%d",&a,&b,&c);
map[a][b]=-c;
}
for(int i=1;i<=n;i++)
map[0][i]=0;
if(SPFA())
puts("YES");
else
puts("NO");
}
return 0;
}
#include<queue> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INF 0x3f3f3f3f #define MAXN 6000 int dis[MAXN],head[MAXN],num[MAXN],vis[MAXN]; int n,m,w; int top; struct node { int v,w,next; }path[MAXN]; void add(int u,int v,int w) { path[top].v=v; path[top].w=w; path[top].next=head[u]; head[u]=top++; } bool SPFA() { memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); for(int i=1;i<=n;i++) dis[i]=INF; queue<int>q; vis[1]=1; dis[1]=0; q.push(1); num[1]++; while(q.size()) { int p=q.front(); q.pop(); vis[p]=0; for(int i=head[p];i!=-1;i=path[i].next){ int t=path[i].v; if(dis[t]>dis[p]+path[i].w){ dis[t]=dis[p]+path[i].w; if(vis[t]==0){ vis[t]=1; q.push(t); num[t]++; if(num[t]>n) return true; } } } } return false; } int main() { int T; //freopen("in.txt","r",stdin); scanf("%d",&T); while(T--) { top=0; scanf("%d%d%d",&n,&m,&w); memset(head,-1,sizeof(head)); int a,b,c; for(int i=1;i<=m;i++){ scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } for(int i=1;i<=w;i++){ scanf("%d%d%d",&a,&b,&c); add(a,b,-c); } if(SPFA()) puts("YES"); else puts("NO"); } return 0; }
相关文章推荐
- DWR框架学习
- 材质ID随机生成器使用教程
- 最近公共祖先LCA问题(转)
- QT 5.3开发及移植 实例
- linux学习-练习3
- 详解iOS的深浅拷贝
- 简单的看Unicode和UTF-8的区别
- springmvc返回json格式数据报406错误
- checkbox控件应用
- 自定义开关按钮
- STL深入探究(一、空间配置器)
- 兴奋剂检查(vijos 1426)
- Codeforces 702 B. Powers of Two(二分)
- k均值
- swift -- 更改 tableview section header
- 进程间通信笔记(1)—简介
- JAVA动态代理用法与实现过程
- jsp标准标签库
- linux 用户和组管理相关的命令
- PHP关于二叉树的前序中序后序遍历操作