带负权边的单源最短路径-判断是否存在负环-输出最短距离

11 篇文章 0 订阅

 输入一个有向网络图,边的权值可正可负,求顶点到其他各点的最短路。

输入

第一行输入n,表示n个结点(默认顶点为0号)

接下来输入n*n矩阵。表示各边的权值。

输出

输出一行,如果有负权回路输出“not possible”,否则输出顶点0到其他点的最短路,输出答案之间仅有一个空格,结尾没有空格。

样例输入 Copy

4
0 0 -3 0
2 0 0 0
0 -1 0 -4
0 0 0 0

样例输出 Copy

not possible

负权边用 bellmanFord  和 SPFA

此题int范围不行  一直wa不知道原因  改用long long过了

bellmanFord:

#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
#include<algorithm>
#include<queue>
 
using namespace std;

#define INF 0x7fffffff

const long long N = 1001;

long long n;
long long g[N][N];
long long dist[N];

int bellmanFord() {
	for (long long i=1; i<n; i++) {
		dist[i] = INF;
	}
	dist[0] = 0;
	for (long long k=0; k<n; k++) {
		int update = 0;
		for (long long i=0; i<n; i++) {
			for (long long j=0; j<n; j++) {
				if (g[i][j] != INF && dist[i] != INF && dist[j] > dist[i] + g[i][j]) {
					dist[j] = dist[i] + g[i][j];
					update = 1;
				}
			} 
		}
		if (!update) break;
	}
	for (long long i=0; i<n; i++) {
		for (long long j=0; j<n; j++) {
			if (dist[j] > dist[i] + g[i][j]) return 1;
		}
	}
	return 0;
}

int main() {
	while (~scanf("%lld", &n)) {
		memset(g, 0, sizeof(g));
		memset(dist, 0, sizeof(dist));
		long long val;
		for (long long i=0; i<n; i++) {
			for (long long j=0; j<n; j++) {
				scanf("%lld", &val);
				if (val == 0 && i != j) g[i][j] = INF;
				else g[i][j] = val;
			}
		}
		int flag = bellmanFord();
		if (flag) printf("not possible\n");
		else {
			for (long long i=1; i<n; i++) {
				if (i == 1) printf("%lld", dist[i]);
				else printf(" %lld", dist[i]);
			}
			printf("\n");
		} 
	}
	
	return 0;
}

SPFA:

#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
#include<algorithm>
#include<queue>
 
using namespace std;

#define INF 0x7fffffff

const long long N = 100101;

long long n, m;
long long visit[N], dist[N], cnt[N];
long long e[N], nex[N], w[N], now[N];
long long idx;

void add(long long a, long long b, long long c) {
	e[idx] = b;
	w[idx] = c;
	nex[idx] = now[a];
	now[a] = idx++;
}

bool spfa() { 
	queue<long long> que;
	que.push(1);
	dist[1] = 0;
	visit[1] = 1;
	while (!que.empty()) {
		long long p = que.front();
		que.pop();
		visit[p] = 0;
		for(long long i=now[p]; i!=-1; i=nex[i]) {
			long long j = e[i];
			if (dist[j] > dist[p] + w[i]) {
				dist[j] = dist[p] + w[i];
				cnt[j] = cnt[p] + 1;
				if (cnt[j] >= n) return 1;
				if (!visit[j]) {
					que.push(j);
					visit[j] = 1;
				}
			}
		}
	}
	return 0;
}


int main() {
	while(~scanf("%lld",&n)) {
		memset(now, -1, sizeof(now));
		memset(e, 0, sizeof(e));
		memset(nex, 0, sizeof(nex));
		memset(w, 0, sizeof(w));
		long long val;
		idx = 0;
		for(long long i=1; i<=n; i++){
			for (long long j=1; j<=n; j++) {
				scanf("%lld", &val);
				if (val == 0 && i != j) add(i, j, INF);
				else add(i, j, val);
			}
		}
		memset(dist, 0x3f, sizeof(dist));
		memset(cnt, 0, sizeof(cnt));
		memset(visit, 0, sizeof(visit));
		int flag = spfa();
		if (flag) printf("not possible\n");
		else {
			for (int i=2; i<=n; i++) {
				if (i == 2) printf("%lld", dist[i]);
				else printf(" %lld", dist[i]);
			}
			printf("\n");
		} 
	}
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值