Can Dijkstra be used when there are negative edges and no negative rings?

Most people should have thought about this question: can Dijkstra work with negative sides but no negative rings?

I've read a lot of answers and tried some blog examples, but the result of code verification is that Dijkstra is right. In the end, I didn't find a blog to convince me.

I found that there is a limit to looking for a blog, so CSDN, I can't find it!

Of course, I couldn't answer in the end.

But I made an interesting attempt: to shoot.
Show results first:

There's no difference in shooting many times!

Let's talk about my specific practice.

Catalog

1. Code display

2. Result display

3. Useless summary

1. Code display

Let's release my code! All the officials (if any) can test it.

Dijkstra code

Tested by luogu!

/*

It is said that it can only be used when there is no negative edge\
Better than SPFA at this time\ 

*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define INF (1e9+7)
const int N=1e5+10, M=2e5+10;

struct Edge { int to, next, w; }e[M];

struct Node
{
	int v, d;
	bool operator<(const Node & a) const{ return d>a.d; }
};
priority_queue<Node> Q;

int n, m, s;
int d[N], head[N];

void add(int u, int v, int w)
{
	static int en=0;
	e[++en]=(Edge){v,head[u],w};
	head[u]=en;
	return;
}

void Dijkstra(int s)
{
	while(!Q.empty()) Q.pop();
	fill(d,d+n+1,INF);
	d[s]=0;
	Q.push((Node){s,0});
	while(!Q.empty())
	{
		Node cur=Q.top(); Q.pop();
		int v=cur.v;
		if(cur.d!=d[v]) continue;
		for(int h=head[v], vv; h; h=e[h].next)
		{
			vv=e[h].to;
			if(d[vv]>d[v]+e[h].w)
			{
				d[vv]=d[v]+e[h].w;
				Q.push((Node){vv,d[vv]});
			}
		}
	}
	return;
}

int main()
{
	freopen("data.txt","r",stdin);
	freopen("Dijkstra.txt","w",stdout);
	scanf("%d%d%d", &n, &m, &s);
	for(int i=0, u, v, w; i<m; ++i)
	{
		scanf("%d%d%d", &u, &v, &w);
		add(u,v,w);
	}
	Dijkstra(s);
	for(int i=1; i<=n; ++i) printf("%d ", d[i]);
	puts("");
	fclose(stdin); fclose(stdout);
	return 0;
} 

BFS version of SPFA

Tested by luogu!

/*

Negative loop
SPFA_BFS Original version 
Most complex O(nm)\
It is said that SLF and LLL can be optimized\ 

*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=2010, M=3010, INF=1e9+7;
//edge
struct Edge
{
	int to, next, w;
}e[M<<1];

int pn, h[N];
void add(int u, int v, int w)
{
	e[++pn]=(Edge){v,h[u],w};
	h[u]=pn;
	return;
}
//main
int n, m, s;
int d[N];

void init()
{
	memset(h,0,sizeof(h));
	pn=0;
}
//spfa
queue<int> Q;
bool vis[N];
int cnt[N];
bool spfa_bfs(int s)
{
	memset(vis,false,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	fill(d+1,d+n+1,INF); d[s]=0;
	while(!Q.empty()) Q.pop();
	Q.push(s); vis[s]=true;
	
	while(!Q.empty())
	{
		int u=Q.front(); Q.pop();
		vis[u]=false;
		for(int h1=h[u]; h1; h1=e[h1].next)
		{
			int v=e[h1].to;
			if(d[v]>d[u]+e[h1].w)
			{
				d[v]=d[u]+e[h1].w;
				if(!vis[v])
				{
					Q.push(v);
					vis[v]=true;
					cnt[u]++;
					if(cnt[u]>n) return false;
				}
			}
		}
	}
	return true;
}

int main()
{
	freopen("data.txt","r",stdin);
	freopen("SPFA_BFS.txt","w",stdout);
	init();
	scanf("%d%d%d", &n, &m, &s);
	for(int i=0, u, v, w; i<m; ++i)
	{
		scanf("%d%d%d", &u, &v, &w);
		add(u,v,w);
	}
	if(!spfa_bfs(s)) puts("A"); 
// If there is A negative loop that can be reached, output "A" to the beat 
	else
	{
		for(int i=1; i<=n; ++i) printf("%d ", d[i]);
		puts("");
	}
	fclose(stdin); fclose(stdout);
	return 0;
}

Random data generation

Maybe the data is unscientific, but at least there are negative edges and no negative rings.

/*

About 1 / 20 of the data randomly generated by the program is negative.
There are at most n=200 points, at least 2*n, and at most 2400 edges.

*/
#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
#define M1 200
#define M2 2000
#define M3 2000
#define RAND(x) (rand()%(x)+1)

int main()
{
	freopen("data.txt","w",stdout);
	srand((unsigned)time(NULL));
	int n, m, s;
	n=RAND(M1); m=n*2+RAND(M2); s=RAND(n);
	printf("%d %d %d\n", n, m, s);
	for(int i=0, u, v, w; i<m; ++i)
	{
		u=RAND(n);
		v=RAND(n);
		w=RAND(M3);
		if(w%20==0) w=-w/10;
		printf("%d %d %d\n", u, v, w);
	}
	fclose(stdout);
	return 0;
}

Beat program

It's good to be a template directly.

#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
#define getTime(a,b) (double)((b)-(a))/CLOCKS_PER_SEC

int main()
{
	int cnt=0;
	while(1)
	{
		system("data.exe");
		
		clock_t startTime1=clock();
		system("SPFA_BFS.exe");
		clock_t endTime1=clock();
		printf("oh,man~\n");
		
		FILE *f1=fopen("SPFA_BFS.txt","r");
		char c=fgetc(f1);
		fclose(f1);
		if(c=='A') continue;
	// First, use SPFA to judge whether there is a negative ring, if so, re random data
	
		clock_t startTime2=clock();
		system("Dijkstra.exe");
		clock_t endTime2=clock();
		
		printf("run time : %lf  %lf\n", getTime(startTime1,endTime1), \
										getTime(startTime2,endTime2));
		
		if(system("fc SPFA_BFS.txt Dijkstra.txt"))
		{
			printf("failed.");
			system("data.txt");
			return 0;
		}

// Take a little note
		cnt++;
		if(cnt%20==0)
		{
			printf("------------------------------The first %d Times--------\n\n", cnt); 
		}
	}
}

The code is finished.
Feel your body hollowed out

3. Result display

First, let's see how the data goes:

Looking for any one of the data, we can see that there is a negative side, which is more reasonable.

Let's see how the shortest circuit of each point is:

Yes, the shortest path from the starting point to each terminal point is also normal, only a few are INF, which is acceptable.

Last and last:

Happy new year 2020!!!

summary

In my attempt, Dijkstra didn't lose! Although said by countless people, but did not give in!

But what's the use?

When there is no negative boundary, Dijkstra is still used 1 The tragedy of changing from 100 to 60 still reverberates in some people's minds; when there is a negative side, people still prefer SPFA, after all, it has been tested for a long time.

Nothing seems to have changed.

  1. 2018 NOI D1T1 ↩︎

28 original articles published, praised 7, 4635 visitors
Private letter follow

Posted on Tue, 14 Jan 2020 05:46:07 -0500 by cornercuttinjoe