UVA - 558 Wormholes (Bellman-ford)

题目大意:
在公元2163年,人类发现了虫洞,虫洞是连接时间和两个星系的隧道。
于是就有些疯狂的科学家题意,要穿越到时间的尽头,看宇宙大爆炸。
现在给你n个点和m条边,没条边都有两个端点和一个权值。
如果权值 > 0,就表示这个虫洞,能穿越到未来。
权值 < 0,就表示这个虫洞,能穿越到从前。
现在问你科学家能否穿越到时间的尽头,看宇宙大爆炸。

解析:
最近很流行的电影《时空穿越》,讲的就是人类从一个星系穿越到另一个星系。

能否无限穿越到从前,就是问是否存在一个负环。这里可以用Bellman_ford算法来判断。

Bellman_ford算法模板:

前面先遍历n-1是代表最坏的情况是遍历n-1,求出最优的解,继续第n次操作,最优解应当和第n-1次操作相同,如果不同,那么就是存在负环。

bool bellman_ford(int s) {
	for(int i = 0; i < n; i++) {
		d[i] = INF;
	}
	d[s] = 0;
	int x ,y;
	for(int k = 0; k < n-1; k++) { //迭代n-1次
		for(int i = 0; i < m; i++) { //检查每条边
			x = u[i], y = v[i];
			if(d[x] < INF) {
				d[y] = min(d[y], d[x] + w[i]);
			}
		}
	}
	for(int i = 0; i < m; i++) {
		x = u[i] , y = v[i];
		int tmp = d[y];
		d[y] = min(d[y], d[x] + w[i]);
		if(d[y] != tmp) {
			return false;
		}
	}
	return true;
}

AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 2005;
const int INF = 0x3f3f3f3f;
int u[maxn],v[maxn],w[maxn];
int d[maxn];
int n,m;
bool bellman_ford(int s) {
	for(int i = 0; i < n; i++) {
		d[i] = INF;
	}
	d[s] = 0;
	int x ,y;
	for(int k = 0; k < n-1; k++) { //迭代n-1次
		for(int i = 0; i < m; i++) { //检查每条边
			x = u[i], y = v[i];
			if(d[x] < INF) {
				d[y] = min(d[y], d[x] + w[i]);
			}
		}
	}
	for(int i = 0; i < m; i++) {
		x = u[i] , y = v[i];
		int tmp = d[y];
		d[y] = min(d[y], d[x] + w[i]);
		if(d[y] != tmp) {
			return false;
		}
	}
	return true;
}
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]);
		}
		int ok = bellman_ford(0);
		if(ok) {
			printf("not possible\n");
		}else {
			printf("possible\n");
		}
	}
	return 0;
}

用邻接表的方法:

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1005;
struct Edge {
	int from ,to ,dist;
	Edge(int u,int v,int d) {
		from = u;
		to = v;
		dist = d;
	}
};
struct Bellman {
	int n,m;
	vector<Edge> edges;
	vector<int> G[maxn];
	bool done[maxn];
	int d[maxn];
	int p[maxn];
	int inq[maxn],cnt[maxn];
	void init(int n) {
		this->n = n;
		for(int i = 0; i < n; i++) {
			G[i].clear();
		}
		edges.clear();
	}
	void addEdge(int from,int to,int dist) {
		edges.push_back(Edge(from, to, dist));
		m = edges.size();
		G[from].push_back(m-1);
	}
	bool bellman_ford(int s) {
		queue<int> Q;
		memset(inq,0,sizeof(inq));
		memset(cnt,0,sizeof(cnt));
		for(int i = 0; i < n; i++) {
			d[i] = INF;
		}
		d[s] = 0;
		inq[s] = true;
		Q.push(s);
		while(!Q.empty()) {
			int u = Q.front();
			Q.pop();
			inq[u] = false;
			for(int i = 0; i < G[u].size(); i++) {
				Edge& e = edges[G[u][i]];
				if(d[u] < INF && d[e.to] > d[u] + e.dist) {
					d[e.to] = d[u] + e.dist;
					p[e.to] = G[u][i];
					if(!inq[e.to]) {
						Q.push(e.to);
						inq[e.to] = true;
						if(++cnt[e.to] > n) {
							return false;
						}
					}
				}
			}
		}
		return true;
	}
};
int main() {
	Bellman bell;
	int T;
	int n,m;
	int u,v,dist;
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&n,&m);
		bell.init(n);
		for(int i = 0; i < m; i++) {
			scanf("%d%d%d",&u,&v,&dist);
			bell.addEdge(u,v,dist);
		}
		int ok = bell.bellman_ford(0);
		if(!ok) {
			printf("possible\n");
		}else {
			printf("not possible\n");
		}
	}
	return 0;
}


你可能感兴趣的:(uva,558,Wormholes)