首页 > uva 558 Wormholes

uva 558 Wormholes

算是模板题,给定一个有向图,顶点从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 
#include 
#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; iINF;d[s]=0;for(k=1; k//进行V-1次松弛for(int i=0; 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//检查一遍所有的边
    {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)scanf("%d%d%d",&u[i],&v[i],&w[i]);if(!BF(0))  //有负环printf("possible
");elseprintf("not possible
");}return 0;
}

 

SPFA_BFS

#include 
#include 
#include 
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("打印邻接表:
");for(int i=0; i*/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
");elseprintf("not possible
");}return 0;
}

 

SPFA_DFS

//时间最快0.008
#include 
#include 
#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("打印邻接表:
");for(int i=0; i*/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){ vis[i]=0; d[i]=INF;}d[0]=0;if(spfa_dfs(0))  printf("possible
");else     printf("not possible
");}return 0;
}    

 

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

#include 
#include 
#include 
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("打印邻接表:
");for(int i=0; i*/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//枚举所有源点
        {int tmp=spfa_bfs(s) ;//for(int i=0; i//printf("%d ",d[i]);//printf("
");if(!tmp)  break;}if(s//有负环printf("possible
");elseprintf("not possible
");}return 0;
}

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

更多相关:

  •         Apache POI是一个开源的利用Java读写Excel,WORD等微软OLE2组件文档的项目。        我的需求是对Excel的数据进行导入或将数据以Excel的形式导出。先上简单的测试代码:package com.xing.studyTest.poi;import java.io.FileInputSt...

  • 要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。 要取得a到b之间的...

  • 利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) image,计算图像的reflectance image。 Reflectance Image 是指在变化的光照条件下能够维持不变的图像部分...

  • 题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 解题: cl...

  • 题目:二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树:      5     /    2   6   /  1   3示例 1: 输入: [1,6,3,2,5] 输出...

  • 用python编写乘法口诀表的方法 发布时间:2020-08-25 11:46:35 来源:亿速云 阅读:60 作者:小新 用python编写乘法口诀表的方法?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧! 第一种:使用for遍历循环嵌套for x in...

  • //很长一段时间我都只使用以下方式做数组循环,具体原因看数据 var aa = for (var i = 0, l = aa.length; i < l; i++) { var a = aa[i];} 数据采集图片来源于网友 很明显,for循环第二种方式完胜!!! 至于for in、forEach什么的,不知道甩他们多少...

  • 目录 1. Scene Graph Generation with External Knowledge and Image Reconstruction 2. Knowledge Acquisition for Visual Question Answering via Iterative Querying Author...

  • 基础题1: 输入一个正整数 n (1≤n≤10)和n 阶方阵a的元素,如果方阵a中的所有元素都沿主对角线对称,输出“Yes”, 否则,输出“No”。主对角线为从矩阵的左上角至右下角的连线,方阵a中的所有元素都沿主对角线对称指对所有i, k,a[i][k]和a[k][i]相等。输入输出示例如下: 输入: 3 1 2 3 4 5 6 7...

  • 程序流程控制 分支 顺序 循环 if switch&case 1 2 3 调整 break 1.6 前 switch(byte、short、char、int) 1.7 可放String 循环 while(次数不确定) do while for(确定次数) break(跳出本层循环) continue(跳出本次循环)     *   2...