题目大意:
在公元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;
}