算是模板题,给定一个有向图,顶点从0到n-1编号,必须从0开始出发,问是否存在负环

一开始写了一个Bellman-Ford,超时,然后就放弃了,写了个spfa的bfs版本,过了,然后又写了一个spfa的dfs版本,wa,然后改了一个下午,还是wa

然后上网找了一下代码,发现很多人写的都是BF算法,看了一下自己的一样,怎么会超时呢??

后来才发现,我读错题意了,我本来是理解为只要图中有负环就好了,所有枚举了所有的顶点作为源点去BF,所以才超时,现在是规定了0作为源点,所以就AC了

然后就把spfa的dfs版本改了一下,不要枚举所有源点,规定0为源点,然后就AC了,再修改了一些细节地方,跑出了最好成绩0.008排名第5

从这个地方可以看出,数据中,有的图是不连通的,所以有的连通分量有负环有的没有,如果枚举了所以的源点的话,有可能会WA

但是有个地方比较困惑,我第一次写spfa的bfs版本的时候也是枚举了所有源点的,可以AC,照理来说应该是WA的,然后改为单源点后也是AC,是数据问题??不可能啊

希望有人指点一下

下面给出代码

Bellman-Ford

#include <cstdio>
#include <cstring>
#define N 1010
#define M 2010
#define INF 0x3f3f3f3f
int d[N],u[M],v[M],w[M];
int n,m;int BF(int s)  //Bellman-Ford
{int k,i,j;for(i=0; i<n; i++) d[i]=INF;d[s]=0;for(k=1; k<n; k++)  //进行V-1次松弛for(int i=0; i<m; i++)  //枚举所有的边
        {int x=u[i],y=v[i];if( d[x]+w[i] < d[y] )d[y]=d[x]+w[i];}int OK=1;for(int i=0; i<m; i++)  //检查一遍所有的边
    {int x=u[i],y=v[i];if( d[x]+w[i] < d[y] )  //还能进行松弛
        {OK=0;break;}}return OK;
}
int main()
{int T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);for(int i=0; i<m; i++)scanf("%d%d%d",&u[i],&v[i],&w[i]);if(!BF(0))  //有负环printf("possible\n");elseprintf("not possible\n");}return 0;
}

SPFA_BFS

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define N 1010
#define NN 5
#define M 2010
#define INF 0x3f3f3f3f
int n,m;
int d[N],f[N],nnext[M],u[M],v[M],w[M];  //用数组来模拟邻接表,并且使用头插法
int c[N];  //记录每个顶点进队的次数
bool vis[N];  //标记顶点在队内void input()
{scanf("%d%d",&n,&m);memset(f,0,sizeof(f));//memset(nnext,0,sizeof(nnext));for(int i=1; i<=m; i++)  //边集数组从下标1保存到m
    {scanf("%d%d%d",&u[i],&v[i],&w[i]);nnext[i]=f[u[i]];  //头插法f[u[i]]=i;        //头插法
    }
/*printf("打印邻接表:\n");for(int i=0; i<n; i++){printf("%d:\n",i);int j=f[i];while(j!=0){printf("%d %d\n",v[j],w[j]);j=nnext[j];}}
*/return ;
}int spfa_bfs(int s)
{queue <int> q;memset(d,0x3f,sizeof(d));d[s]=0;memset(c,0,sizeof(c));memset(vis,0,sizeof(vis));q.push(s);  vis[s]=1; c[s]=1;//顶点入队vis要做标记,另外要统计顶点的入队次数int OK=1;while(!q.empty()){int x;x=q.front(); q.pop();  vis[x]=0;//队头元素出队,并且消除标记for(int k=f[x]; k!=0; k=nnext[k]) //遍历顶点x的邻接表
        {int y=v[k];if( d[x]+w[k] < d[y]){d[y]=d[x]+w[k];  //松弛if(!vis[y])  //顶点y不在队内
                {vis[y]=1;    //标记c[y]++;      //统计次数q.push(y);   //入队if(c[y]>NN)  //超过入队次数上限,说明有负环return OK=0;}}}}return OK;}
int main()
{int T;scanf("%d",&T);while(T--){input();if(!spfa_bfs(0))  //有负环printf("possible\n");elseprintf("not possible\n");}return 0;
}

SPFA_DFS

//时间最快0.008
#include <cstdio>
#include <cstring>
#define N 1010
#define M 2010
#define INF 0x3f3f3f3f
int d[N],f[N];
bool vis[N];
struct edge
{int u,v,w,next;}e[M];
int n,m;void input()
{scanf("%d%d",&n,&m);memset(f,0,sizeof(f));for(int i=1; i<=m; i++)  //读入所有边
    {scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);int u=e[i].u;e[i].next=f[u];f[u]=i;}
/*printf("打印邻接表:\n");for(int i=0; i<n; i++){printf("%d:\n",i);for(int k=f[i]; k!=0; k=e[k].next)printf("%d %d\n",e[i].v,e[i].w);}
*/return ;
}int spfa_dfs(int u)
{vis[u]=1;for(int k=f[u]; k!=0; k=e[k].next){int v=e[k].v,w=e[k].w;if( d[u]+w < d[v] ){d[v]=d[u]+w;if(!vis[v]){if(spfa_dfs(v))return 1;}elsereturn 1;}}vis[u]=0;return 0;
}
int main()
{int T;scanf("%d",&T);while(T--){input();for(int i=0; i<n; i++){ vis[i]=0; d[i]=INF;}d[0]=0;if(spfa_dfs(0))  printf("possible\n");else     printf("not possible\n");}return 0;
}    

求指教  SPFA_BFS  枚举所有起点,按道理应该是WA的,为什么AC了…………

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define N 1010
#define NN 5
#define M 2010
#define INF 0x3f3f3f3f
int n,m;
int d[N],f[N],nnext[M],u[M],v[M],w[M];  //用数组来模拟邻接表,并且使用头插法
int c[N];  //记录每个顶点进队的次数
bool vis[N];  //标记顶点在队内void input()
{scanf("%d%d",&n,&m);memset(f,0,sizeof(f));//memset(nnext,0,sizeof(nnext));for(int i=1; i<=m; i++)  //边集数组从下标1保存到m
    {scanf("%d%d%d",&u[i],&v[i],&w[i]);nnext[i]=f[u[i]];  //头插法f[u[i]]=i;        //头插法
    }
/*printf("打印邻接表:\n");for(int i=0; i<n; i++){printf("%d:\n",i);int j=f[i];while(j!=0){printf("%d %d\n",v[j],w[j]);j=nnext[j];}}
*/return ;
}int spfa_bfs(int s)
{queue <int> q;memset(d,0x3f,sizeof(d));d[s]=0;memset(c,0,sizeof(c));memset(vis,0,sizeof(vis));q.push(s);  vis[s]=1; c[s]=1;//顶点入队vis要做标记,另外要统计顶点的入队次数int OK=1;while(!q.empty()){int x;x=q.front(); q.pop();  vis[x]=0;//队头元素出队,并且消除标记for(int k=f[x]; k!=0; k=nnext[k]) //遍历顶点x的邻接表
        {int y=v[k];if( d[x]+w[k] < d[y]){d[y]=d[x]+w[k];  //松弛if(!vis[y])  //顶点y不在队内
                {vis[y]=1;    //标记c[y]++;      //统计次数q.push(y);   //入队if(c[y]>NN)  //超过入队次数上限,说明有负环return OK=0;}}}}return OK;}
int main()
{int T;scanf("%d",&T);while(T--){input();int s;for(s=0; s<n; s++)  //枚举所有源点
        {int tmp=spfa_bfs(s) ;//for(int i=0; i<n; i++)//printf("%d ",d[i]);//printf("\n");if(!tmp)  break;}if(s<n)  //有负环printf("possible\n");elseprintf("not possible\n");}return 0;
}

转载于:https://www.cnblogs.com/scau20110726/archive/2012/11/24/2786249.html

uva 558 Wormholes相关推荐

  1. UVaOJ 558 - Wormholes

    --by A Code Rabbit Description 所谓虫洞就是穿过去,可以回到过去! 这种牛逼的东西,大家天马行空开始幻想. 输入一张宇宙图,图中某些边权值为负,即为虫洞. 输出有木有办法 ...

  2. UVA 558 SPFA 判断负环

    这个承认自己没看懂题目,一开始以为题意是形成环路之后走一圈不会产生负值就输出,原来就是判断负环,用SPFA很好用,运用队列,在判断负环的时候,用一个数组专门保存某个点的访问次数,超过了N次即可断定有负 ...

  3. π-Algorithmist分类题目(2)

    原题网站:Algorithmist,http://www.algorithmist.com/index.php/Main_Page π-Algorithmist分类题目(2) Set Theory U ...

  4. UVa Online Judge 工具網站

    UVa Online Judge 工具網站 转自http://www.csie.ntnu.edu.tw/~u91029/uva.html Lucky貓的ACM園地,Lucky貓的 ACM 中譯題目 M ...

  5. 提取了下刘汝佳推荐的题号...

    今天闲来没事上uva oj提取了下刘汝佳推荐的acm题号,原始数据如下: Volume 0. Getting Started    10055 - Hashmat the Brave Warrior ...

  6. 紫书《算法竞赛入门经典》

    紫书<算法竞赛入门经典>题目一览 第3章 数组和字符串(例题) UVA 272 TEX Quotes UVA 10082 WERTYU UVA 401 Palindromes UVA 34 ...

  7. 初学者acm的练习题指南

    上机练习题参考题 忘了在哪找的啦~~希望对大家有帮助呦 <!--[if !supportLists]-->1.    <!--[endif]-->Programming Bas ...

  8. [搜索]UVa 129 困难的串

    题意:将一个包含两个相邻的重复子串的子串,称为"容易的串",其他为"困难的串". 输入正整数n和l,输出由前l个字符组成的,字典序第n小的困难的串. 输入样例: ...

  9. uva 401.Palindromes

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...

最新文章

  1. MSI文件制作全过程
  2. 【重磅】谷歌2021博士奖研金完整名单出炉,13个方向共75人获奖
  3. angular元素属性绑定_【Angular】表单
  4. SeekBar的使用(一):实现OnSeekBarChangListener
  5. shell开发跳板机功能脚本
  6. Eclipse出现Class Not Found异常时可以参考我所知道的一个方案
  7. 给 Android 开发人员的 RxJava 具体解释
  8. VHDL中的转换函数
  9. MySQL之表的约束
  10. leetcode445. 两数相加 II
  11. win7系统设置开机自动联网的方法
  12. C语言字母的压缩,C语言字符串快速压缩算法代码
  13. Vscode下中文乱码问题
  14. reimage许可证密钥_思科 ASA 和 Firepower 威胁防御重新映像指南
  15. 2021-05-15 随机生成车架号
  16. android tf卡 修复工具,SD卡恢复修复工具RecoveRx 3.2中文免费版
  17. git添加文件到版本库中
  18. 使用 TestFlight 进行 iOS App 内测
  19. airtest上的滑动操作swipe
  20. 快速可靠网络传输协议 KCP

热门文章

  1. 全球及中国家用除湿机行业消费需求调研及十四五发展趋势研究报告2022-2027年
  2. 消费扶贫谋定中国农民丰收节交易会 洛水山肴乡村振兴
  3. Go 面向对象编程应用
  4. sql server set赋值和select 赋值的区别以及使用方法
  5. Python 中的*args和**kwargs
  6. RabbitMQ 最常用的三大模式
  7. vsCode 开发微信小程序插件
  8. 转-eclipse管理多个workspace
  9. SignalR系列教程:SignalR快速入门
  10. mysql数据库操作语句大全