SPFA算法

难点: 1. 起始点有自环, 不管正环或者负环, 都需要去判断是VOID还是UNBOUND;

2. 判断负权环是否存在于路径上;(这个算法我一开始想把SPFA某个点进队列次数大于2*n或者更大的数把所有在负环中的点全部找出来,但是有可能做不到,比如从s开始分出2个叉A和B,t在A叉上,A叉上在距离s非常远处有个负环,而B叉上在距离s很近处就有个负环,这样A叉上的负环有可能检查不出来,所以我参考网上的一个算法,感觉没有漏洞,就是从t遍历逆图访问到的点做标记,然后在SPFA时不需要扩展未做标记的点,因为此点不可能到达t。如果有什么不周全的地方,还恳请路过的大牛赐教)

第二种想法代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
#define inf 100000000
using namespace std;
int n,m,s,t;
int head[1200],cnt,head1[1200];
bool vis[1200],sig[1200],ok[1200];
int dis[1200],mon[1200],times[1200];
struct EDGE{int v,f,d,next;
}edge[22000];
void addedge(int u,int v,int f,int d){if(head[u]!=-1 && edge[head[u]].f<f)return;if(head[u]!=-1 && edge[head[u]].f>f)head[u]=-1;edge[cnt].v=v;edge[cnt].d=d;edge[cnt].f=f;edge[cnt].next=head[u];head[u]=cnt++;
}
int SPFA(int u){int i,j;memset(vis,0,sizeof(vis));memset(times,0,sizeof(times));for(i=0;i<n;i++){dis[i]=mon[i]=inf;}queue<int>que;que.push(u);vis[u]=1;dis[u]=mon[u]=0;times[u]++;while(!que.empty()){int tem=que.front();que.pop();vis[tem]=0;                   //把这句移到这里可以把负的自环判断出来if(times[tem]>n)           return 1;for(i=head[tem];i!=-1;i=edge[i].next){int v=edge[i].v;if(!ok[v])continue;if(mon[v]>mon[tem]+edge[i].f || (mon[v] == mon[tem]+edge[i].f && dis[v]>dis[tem]+edge[i].d)){mon[v]=mon[tem]+edge[i].f;dis[v]=dis[tem]+edge[i].d;if(!vis[v]){que.push(v);vis[v]=1;times[v]++;}}}}return 0;
}
void dfs(int a){int i,yes=0;ok[a]=1;for(i=head1[a];i!=-1;i=edge[i].next){if(!ok[edge[i].v])dfs(edge[i].v);}
}
int main(){int i,j;char str[1000];while(scanf("%d %d %d %d",&n,&m,&s,&t)==4){memset(head,-1,sizeof(head));cnt=0;for(i=1;i<=m;i++){int u,v,f1,l,f2;char tem;scanf("%s",str);sscanf(str,"(%d,%d,%d[%d]%d)",&u,&v,&f1,&l,&f2);addedge(u,v,f1,l);addedge(v,u,f2,l);}memset(ok,0,sizeof(ok));memset(head1,-1,sizeof(head1));for(i=0;i<n;i++){                                //建立反图for(j=head[i];j!=-1;j=edge[j].next){edge[cnt].v=i;edge[cnt].next=head1[edge[j].v];head1[edge[j].v]=cnt++;}}dfs(t);                                         //搜索所有能够到达t的点并标记int kk=SPFA(s);if(mon[t]==inf)printf("VOID\n");else if(kk==0)printf("%d %d\n",mon[t],dis[t]);elseprintf("UNBOUND\n");}return 0;
}

第一种想法代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
#define inf 100000000
using namespace std;
int n,m,s,t;
int head[1200],cnt;
bool vis[1200],sig[1200];
int dis[1200],mon[1200],times[1200];
struct EDGE{int v,f,d,next;
}edge[11000];
void addedge(int u,int v,int f,int d){if(head[u]!=-1 && edge[head[u]].f<f)return;if(head[u]!=-1 && edge[head[u]].f>f)head[u]=-1;edge[cnt].v=v;edge[cnt].d=d;edge[cnt].f=f;edge[cnt].next=head[u];head[u]=cnt++;
}
int SPFA(int u){int i,j;memset(vis,0,sizeof(vis));memset(times,0,sizeof(times));for(i=0;i<=n;i++){dis[i]=mon[i]=inf;}queue<int>que;que.push(u);vis[u]=1;dis[u]=mon[u]=0;times[u]++;while(!que.empty()){int tem=que.front();que.pop();vis[tem]=0;                   //把这句移到这里可以把负的自环判断出来if(times[tem]>n*2)            //这里当一个点出现n*2次时,可以把所以环上的点标记好return 1;for(i=head[tem];i!=-1;i=edge[i].next){int v=edge[i].v;if(mon[v]>mon[tem]+edge[i].f || (mon[v] == mon[tem]+edge[i].f && dis[v]>dis[tem]+edge[i].d)){mon[v]=mon[tem]+edge[i].f;dis[v]=dis[tem]+edge[i].d;if(!vis[v]){que.push(v);vis[v]=1;times[v]++;}}}}return 0;
}
bool dfs(int a){int i;sig[a]=1;if(a==t)return 1;for(i=head[a];i!=-1;i=edge[i].next){if(!sig[edge[i].v]){dfs(edge[i].v);}}return 0;
}
int main(){int i,j;char str[1000];while(scanf("%d %d %d %d",&n,&m,&s,&t)==4){memset(head,-1,sizeof(head));cnt=0;for(i=1;i<=m;i++){int u,v,f1,l,f2;char tem;scanf("%s",str);sscanf(str,"(%d,%d,%d[%d]%d)",&u,&v,&f1,&l,&f2);addedge(u,v,f1,l);addedge(v,u,f2,l);}int kk=SPFA(s);if(mon[t]==inf)printf("VOID\n");else if(kk==0)printf("%d %d\n",mon[t],dis[t]);else{bool flag=0;memset(sig,0,sizeof(sig));for(i=0;i<n;i++){if(times[i]>n){if(!sig[i]){flag=dfs(i);if(sig[t])break;}}}if(sig[t])printf("UNBOUND\n");elseprintf("%d %d\n",mon[t],dis[t]);}}return 0;
}

POJ 2679 Adventurous Driving相关推荐

  1. poj 2679 Adventurous Driving(SPFA 负环)

    /* - - 这题做了一天.....粗心害死人啊 题目描述恶心 数据更恶心... 先处理一下能走的边 能走的点(到这建边从终点跑一下.) 然后就是SPFA了 注意负环的判断 */ #include&l ...

  2. 2679 Adventurous Driving 解题报告

    Memory: 324K Time: 0MS Language: G++ Faults:20 wa + ... Algorithm:最短路径 #include <stdio.h> #inc ...

  3. poj2679 Adventurous Driving 最短路

    http://poj.org/problem?id=2679 写完这道题内心是崩溃的, 写个题解纪念一下 题意: 给你n个点m条边,起点是st,终点是end,给你一些边,这些边带有费用和长度,让你求从 ...

  4. UVALIVE 3307 Adventurous Driving

    一开始重新建图搞的.然后参照了别人的博客.这个解法比较好 利用在SPFA维护入队次数.入队次数大于节点数目的位于负环. 那么负环中的点如何DFS到终点.(SPFA从起点开始如果能找到入队大于N那么一定 ...

  5. 转:POJ先做完这50题再说

    POJ推荐50题 POJ == 北京大学ACM在线评测系统 http://acm.pku.edu.cn/JudgeOnline 1. 标记 难 和 稍难 的题目大家可以看看,思考一下,不做要求,当然有 ...

  6. poj题目分类(转)--方便分类做题

    POJ推荐50题以及ACM训练方案(转) POJ 推荐50题 第一类 动态规划(至少6题,2479 和 2593 必做) 2479 和 2593 1015 1042(可贪心)  1141 1050 1 ...

  7. Poj·Picnic Planning

    初见安~这里是传送门:Poj P1639 Description The Contortion Brothers are a famous set of circus clowns, known wo ...

  8. POJ 3268 D-Silver Cow Party

    http://poj.org/problem?id=3268 Description One cow from each of N farms (1 ≤ N ≤ 1000) conveniently ...

  9. poj 2559 Largest Rectangle in a Histogram 栈

    // poj 2559 Largest Rectangle in a Histogram 栈 // // n个矩形排在一块,不同的高度,让你求最大的矩形的面积(矩形紧挨在一起) // // 这道题用的 ...

最新文章

  1. [BZOJ2502]清理雪道 有上下界网络流(最小流)
  2. 创建虚拟机并安装CentOS操作系统
  3. python图片-Python图像处理
  4. 数据结构——树、二叉树、森林、哈夫曼树、字符串模式匹配
  5. Ubuntu返回到Gnome经典桌面!
  6. caffe matio问题
  7. 解析微服务架构与最佳实践
  8. s7.net 写数据到plc_机器视觉软件开发系列——松下PLC下位机通信协议简介和实现...
  9. matlab程序 surf算法,【求大神帮忙,surf算法源代码解析】
  10. 命运的拐弯处,那份竭尽全力拯救自己的韧性
  11. iOS之有用的分类(UsefulCategory)
  12. 用报初会的照片报计算机,会计考试报名倒计时,手把手教你一次通过审核工具...
  13. Extjs之EditorGridPanel的beforeedit事件参数
  14. 计算机小型机是机箱么,广州励康科技
  15. 127.0.0.1 zxt.php_php单文件版在线代码编辑器使用方法
  16. just for save
  17. 在金融公司做 IT 是什么感觉?
  18. 蜂巢贷:车抵贷款和房屋抵押贷款的区别
  19. Js逆向教程22-AST 抽象语法树babel安装
  20. PMP学习笔记之一 准备篇

热门文章

  1. MD5数字签名算法:生成签名和验签(附代码)
  2. Centos8.3 nfs-ganesha使用vfs共享目录
  3. 服务器显示ipv4有两个ip地址,怎么解决windows7 ipv4获得2个IP地址
  4. 如何在Ubuntu上安装flash?
  5. 【2022/08/11】文件的上传(FileUpload)
  6. 信息管理系统平台html加css漂亮后台模板
  7. 计算机无法识别手机咋解决,我电脑不能识别手机USB端口。怎么办?
  8. MySQL:求众数、平均数、中位数
  9. 利用swiper和css3实现手机滑屏与动画效果
  10. Sage X3 ERP如何帮助客户提高库存盘点准确率仓库为什么要多次盘点?