Wormholes(虫洞) 判断负环 + 队列优化Bellman邻接表实现
2019-07-29 20:55
14 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44855285/article/details/97673636
Wormholes 图中有无负环的判断
John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John的每个农场有M条小路(无向边)连接着N (从1…N标号)块地,并有W个虫洞(有向边)。其中1<=N<=500,1<=M<=2500,1<=W<=200。 现在John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。 John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有虫洞回帮你回到超过10000秒以前。
【输入格式】
-
Line 1: 一个整数 F, 表示农场个数。
-
Line 1 of each farm: 三个整数 N, M, W。
-
Lines 2…M+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条用时T秒的小路。
-
Lines M+2…M+W+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条可以使John到达T秒前的虫洞。
【输出格式】
- Lines 1…F: 如果John能在这个农场实现他的目标,输出"YES",否则输出"NO"。
//翻译转载
一个图上有正权边和负权边,判断是否可以构成负权回路。
判断负权回路,那我们要用到Bellman算法了,之前没怎么用过邻接表存图,在这里放一个写的模板。
/* 核心: 原始:枚举每条边,用边收缩到源点的距离,进行n-1次枚举收缩操作(无负环则最多n-1次即可) 队列优化:用边去收缩每个点到源点的距离,边选择到源点的距离改变了的点的临边 一开始把源点放入队列,从队列中取点,用这些点的临边尝试收缩,再把成功收缩了的点放入队列 如果点已经在队列中,就跳过 Bellman和Dijkstra的不同: B的book数组是用来标记点是否在队列中,若点弹出,book就要复0,D的book数组是用了标记是否用这个点为中转收缩过,**每个点只作为中转1次**。 B的队列是普通队列,D的为以到源点距离为判断标准的优先队列 Bellman时间复杂度为n*m,即使优化后,时间复杂度还是玄学,除了处理负权负环外,应使用Dijkstra。(若n*m不会超时间当然可以) */ #include <cstdio> #include <cstring> #include <queue> using namespace std; #define Max 0x3f3f3f3f int node[505],book[505],num[505],dis[505],cnt/*边容量*/; struct E{ int b,c; int next; }e[6000]; void add(int a,int b,int c){ cnt++; e[cnt].b = b; e[cnt].c = c; e[cnt].next = node[a]; node[a] = cnt; } void init(int n,int m){ cnt = 0; memset(node,-1,sizeof(node)); memset(book,0,sizeof(book)); memset(num,0,sizeof(num)); memset(dis,Max,sizeof(dis)); /* for(int i=1; i<=n; i++){ node[i] = -1; book[i] = 0; num[i] = 0; dis[i] = Max; } */ for(int i=1; i<=m; i++) e[i].next=-1; } void Bell(int n){ //n个点 queue<int>que; int f=0; //默认无负环 que.push(1); dis[1] = 0; //判断负环,随便从1号点搜就可以了 book[1] = 1; while(!que.empty()){ int x=que.front(); que.pop(); //取走就弹出 大佬告诉我的好习惯 book[x] = 0; int k=node[x]; while(k!=-1){ int b=e[k].b, c=e[k].c;//x的邻点 if(dis[b]>dis[x]+c){ dis[b] = dis[x]+c; num[b]++; if(num[b]>=n){ f = 1; break; } if(book[b]==0) que.push(b); } k = e[k].next; } if(f==1) break;//有环,无限收缩,退出 } if(f==1) printf("YES\n"); else printf("NO\n"); } int main() { int F, n,m,w; scanf("%d",&F); for(int I=1; I<=F; I++){ scanf("%d%d%d",&n,&m,&w); init(n , m*2+w); for(int i=1; i<=m; i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } for(int i=1; i<=w; i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,-c); } Bell(n); } }
相关文章推荐
- POJ 3259 Wormholes (Bellman-Ford判断负环)
- POJ 3259 Wormholes Bellman判断是否有负环
- 【SPFA判断负环】BZOJ1715- [Usaco2006 Dec]Wormholes 虫洞
- (POJ 3259)Wormholes 判断负环 bellman_ford 或者 spfa
- poj 3259 Wormholes 【Bellman-Ford 判断负环】
- uva 558 Wormholes (Bellman-Ford算法判断负环)
- hdu 1874 畅通工程续 dijsktra dijkstra+邻接表 优先队列 bellman-ford bellman-ford队列优化(基础题目,一步步优化)
- 队列优化并使用邻接表存储的Bellman-Ford算法模板解决最短路径存在负权边问题
- BZOJ2330 差分约束之浅谈数学不等式拓扑逻辑顺序转化为图论中队列实现广度优先搜索的最长路之双端队列Bellman-Ford算法及入队次数判断自环
- 最短路 SPFA 判断负环 静态邻接表(链式前向星) HDU 2544 最短路 POJ 3259 Wormholes
- POJ 3259 Wormholes【bellman_ford判断负环——基础入门题】
- POJ 3259 Wormholes【bellman_ford判断负环——基础入门题】
- Bellman算法优化使用邻接表C++实现
- POJ 3259 Wormholes(判断负环&(Bellman-Ford|SPFA))
- bzoj 1715: [Usaco2006 Dec]Wormholes 虫洞 -- spfa判断负环
- Bellman-Ford队列优化(邻接表)
- POJ 3259 Wormholes (判断负环,SPFA或Bellman-Ford都可)
- POJ 3259 Wormholes(Bellman_Frod判断是否有负环)
- 最短路径(四)—Bellman-Ford的队列优化(邻接表)
- uva 558 - Wormholes(Bellman Ford判断负环)