田里的虫洞

  题目大意:就是这个农夫的田里有一些虫洞,田有很多个点,点与点之间会存在路,走过路需要时间,并且这些点存在虫洞,可以使农夫的时间退回到时间之前,问你农夫是否真的能回到时间之前?

  读完题:这一题就是很明显了,就是要你找负值圈嘛!立马上Bellman_Ford算法

  

#include <iostream>
#include <functional>
#include <algorithm>
#include <queue>
#define MAX_N 501 using namespace std; typedef struct edge_
{
int cost;
int from;
int to;
}Edge;
static Edge Gragh_Edge[MAX_N *MAX_N];
static int dp_edge[MAX_N*MAX_N * + ]; bool Search_Bellman_Ford(const int,const int,const int); int main(void)
{
int Farm_sum, Path_sum, Node_sum, holes_sum, start, end, times;
while (~scanf("%d", &Farm_sum))
{
for (int i = ; i < Farm_sum; i++)
{
scanf("%d%d%d", &Node_sum, &Path_sum, &holes_sum);
for (int j = ; j < * Path_sum; j += )
{
scanf("%d%d%d", &start, &end, &times);
//双向边
Gragh_Edge[j].from = start; Gragh_Edge[j].to = end; Gragh_Edge[j].cost = times;
Gragh_Edge[j + ].from = end; Gragh_Edge[j + ].to = start; Gragh_Edge[j + ].cost = times;
}
for (int j = * Path_sum; j < holes_sum + * Path_sum; j++)
{
scanf("%d%d%d", &start, &end, &times);
Gragh_Edge[j].from = start; Gragh_Edge[j].to = end; Gragh_Edge[j].cost = -times;//单向边,负值,只要覆盖掉之前的正值就可以了
}
if (Search_Bellman_Ford(Node_sum, Path_sum,holes_sum))
printf("YES\n");
else printf("NO\n");
}
}
return ;
} bool Search_Bellman_Ford(const int Node_sum, const int Path_sum, const int holes_sum)
{
int paths = Path_sum * + holes_sum;
memset(dp_edge, , sizeof(dp_edge)); for (int i = ; i < Node_sum; i++)
for (int j = ; j < paths; j++)
{
Edge e = Gragh_Edge[j];
if (dp_edge[e.from] + e.cost < dp_edge[e.to])
{
dp_edge[e.to] = dp_edge[e.from] + e.cost;
if (i == Node_sum - ) return true;
}
}
return false;
}

  结果很高兴地1A了

  当然,这个时间有点慢,我们可以使用SPFA算法优化他

  不过在这之前我们有必要搞清楚什么是SPFA算法,其实这个算法是Bellman_Ford的优化,BF这个算法的缺点在于他一定要把所有的点都扫描n-1次才能确定是否有负值圈,这就造成了低效,而我们知道,其实我们没有必要等所有的节点都到i=n-1的层面,因为如果图不存在负值圈,那么Bellman_Ford以及Dijkstra算法肯定不会经过一个顶点两次,如果存在负圈,那么肯定至少存在一个节点,经过n次以上,那么我们完全可以利用这个性质,在扫n-1次前就找到这个节点,而SPFA算法就是利用这个原理。

  SPFA算法有点像BFS算法,他是充分利用点的关系来找最短路的,而且这个算法还支持负值圈(当然这个算法找正值的最短路径不及Dijkstra那么快),复杂度是O(EV)(没有负值圈的时候),他像BFS一样,不断地把邻接节点入队,然后出队,利用一个used域,我们就可以找到那些不在队中的节点,如果不存在负值圈,那么这些节点就不会经过两次,最终这个算法会以队列为空结束,如果存在负值圈,那么我们需要其他判断方法,这个方法就是判断一个节点是否被进入V次以上(之前说过的性质)。

  其他的也像BF算法一样,还是维护一个dp数组来确定是否更新就可以了

  SPFA因为要对邻接点做处理,所以如果能存边,那就最好了,所以推荐用邻接表,另外ACM因为还是以速度为主,大量的申请内存会导致效率下降,所以如果要维护邻接表,最好还是用向前边的方法维护,就是维护一个head数组,head数组指向第一条边,接下来边指向其他的边就可以了!

  另外这一题因为我们不知道是不是联通,用SPFA还是要稍微判断一下节点有没有经过的问题,没有经过我们就重新设立start节点(这一题讨论版很多人都没考虑到这一点,那是运气好,这一题是联通的,so)

  

 #include <iostream>
#include <functional>
#include <algorithm>
#define MAX_N 501 using namespace std; typedef struct edge_
{
int cost;
int next;
int to;
}Edge;
typedef int Queue, Position;
static Edge Gragh_Edge[MAX_N *MAX_N + ];
static Position head[MAX_N];//用邻接表去存图,这个是节点头
static bool used[MAX_N];//SPFA算法要用到的标记域
static bool known[MAX_N];//判断图是否联通的关键
static int out[MAX_N];//看点出列了多少次
static int dp_edge[MAX_N];//dp数组记录到该点的最短距离
Queue que[MAX_N *MAX_N];//队列 bool Search_Spfa(const int, const int, const int);
void Renew(void); int main(void)
{
int Farm_sum, Path_sum, Node_sum, holes_sum, start, end, times;
while (~scanf("%d", &Farm_sum))
{
for (int i = ; i < Farm_sum; i++)
{
memset(head, -, sizeof(head));
memset(used, , sizeof(used));
memset(known, , sizeof(known));
memset(out, , sizeof(out));
memset(dp_edge, , sizeof(dp_edge));
scanf("%d%d%d", &Node_sum, &Path_sum, &holes_sum);
for (int j = ; j < * Path_sum; j += )
{
scanf("%d%d%d", &start, &end, &times);
//双向边
Gragh_Edge[j].next = head[start]; Gragh_Edge[j].to = end; Gragh_Edge[j].cost = times;
head[start] = j;
Gragh_Edge[j + ].next = head[end]; Gragh_Edge[j + ].to = start; Gragh_Edge[j + ].cost = times;
head[end] = j + ;
}
for (int j = * Path_sum; j < holes_sum + * Path_sum; j++)
{
scanf("%d%d%d", &start, &end, &times);
Gragh_Edge[j].next = head[start]; Gragh_Edge[j].to = end; Gragh_Edge[j].cost = -times;//单向边,负值,只要覆盖掉之前的正值就可以了
head[start] = j;
}
if (Search_Spfa(Node_sum, Path_sum, holes_sum))
printf("YES\n");
else printf("NO\n");
}
}
return ;
} bool Search_Spfa(const int Node_sum, const int Path_sum, const int holes_sum)
{
Position top, bot, out_node; for (int i = ; i <= Node_sum; i++)
{
if (known[i]) continue;
top = bot = ;
known[i] = ; que[bot++] = i; while (top != bot)
{
out_node = que[top++];
known[out_node] = ;
used[out_node] = ;//出队了就标记为0
out[out_node]++;
if (out[out_node] > Node_sum) return true; for (int k = head[out_node]; k != -; k = Gragh_Edge[k].next)//此点的邻接边全部找出来
{
if (dp_edge[Gragh_Edge[k].to] > dp_edge[out_node] + Gragh_Edge[k].cost)
{
dp_edge[Gragh_Edge[k].to] = dp_edge[out_node] + Gragh_Edge[k].cost;
if (!used[Gragh_Edge[k].to])//to不在队列内
{
used[Gragh_Edge[k].to] = ;
que[bot++] = Gragh_Edge[k].to;
}
}
}
}
}
return false;
}

  速度快了一倍

ShortestPath:Wormholes(POJ 3259)的更多相关文章

  1. (最短路 spfa)Wormholes -- poj -- 3259

    http://poj.org/problem?id=3259 Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions ...

  2. Wormholes POJ 3259(SPFA判负环)

    Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes ...

  3. Wormholes - poj 3259 (Bellman-Ford算法)

      Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 34934   Accepted: 12752 Description W ...

  4. kuangbin专题专题四 Wormholes POJ - 3259

    题目链接:https://vjudge.net/problem/POJ-3259 思路:求有无负环,起点随意选就可以,因为目的只是找出有没有负环,有了负环就可以让时间一直回退,那么一定能回到当初,这里 ...

  5. Wormholes POJ - 3259 spfa判断负环

    //判断负环 dist初始化为正无穷 //正环 负无穷 #include<iostream> #include<cstring> #include<queue> # ...

  6. ACM: POJ 3259 Wormholes - SPFA负环判定

     POJ 3259 Wormholes Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu   ...

  7. 最短路(Bellman_Ford) POJ 3259 Wormholes

    题目传送门 /* 题意:一张有双方向连通和单方向连通的图,单方向的是负权值,问是否能回到过去(权值和为负) Bellman_Ford:循环n-1次松弛操作,再判断是否存在负权回路(因为如果有会一直减下 ...

  8. poj - 3259 Wormholes (bellman-ford算法求最短路)

    http://poj.org/problem?id=3259 农夫john发现了一些虫洞,虫洞是一种在你到达虫洞之前把你送回目的地的一种方式,FJ的每个农场,由n块土地(编号为1-n),M 条路,和W ...

  9. POJ 3259 Wormholes(最短路,判断有没有负环回路)

    Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 24249   Accepted: 8652 Descri ...

随机推荐

  1. Hibernate中一级缓存和二级缓存使用详解

    一.一级缓存二级缓存的概念解释 (1)一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个 session(一定要同一个ses ...

  2. 9.Android之日期对话框DatePicker控件学习

    设置日期对话框在手机经常用到,今天来学习下. 首先设置好布局文件:如图 xml对应代码 <?xml version="1.0" encoding="utf-8&qu ...

  3. BZOJ-1003 物流运输trans SPFA+DP

    傻逼错误耗我1h,没给全范围坑我1A.... 1003: [ZJOI2006]物流运输trans Time Limit: 10 Sec Memory Limit: 162 MB Submit: 529 ...

  4. BZOJ-1202 狡猾的商人 并查集+前缀和

    我记得这个题,上次之前做的时候没改完,撂下了,今天突然想改发现,woc肿么A 了= =看来是我记错了.. 1202: [HNOI2005]狡猾的商人 Time Limit: 10 Sec Memory ...

  5. nopCommerce 安装失败: 引发类型为“System.OutOfMemoryException”的异常。

    如果你在安装nopCommerce 3.00版本的时候报如上异常,解决方案: 1.在服务器上检查内存是否已经满了,因为nopCommerce 在安装的时候需要很多内存. 2.关闭占用内存大的进程,保证 ...

  6. HackerRank Ice Cream Parlor

    传送门 Ice Cream Parlor Authored by dheeraj on Mar 21 2013 Problem Statement Sunny and Johnny together ...

  7. POJ3259Wormholes(判断是否存在负回路)

    Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 38300   Accepted: 14095 Descr ...

  8. linux(Debian)下安装与MySql的安装、卸载、配置及使用

    参考资料:http://www.cnblogs.com/xusir/p/3334217.html 以下是简要记录. 一.安装 安装:apt-get install mysql-server mysql ...

  9. 思维固化,addTarget难道就只能给self

    使用前提 调用某个对象的,一个无参数的方法 如[self.view resignFirstResponder] 注意 [self.view endEdting:YES]就不行,要是无参数的

  10. Linux之Sed命令详解(总结一些实用例子)

    简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的 ...