今天更下负权值的最短路,最短路存在,则图中无回路,环(回路)分为零环,负环,正环,若最短路是零环和正环,则去掉此环肯定小于等于原最短路;若为负环,则无最短路,因为会一直负环下去。
若为经典的无环问题,则算法代码如下:
for(int i=0;i<n;i++)
dis[i]=INF;
d[0]=0;
for(int k=0;k<n-1;k++)//共n-1次,也就是除了起始点以外的点
for(int i=0;i<m;i++){//检查没个边
int x=u[i],y=v[i];
if(d[x]<INF) d[y]=min(d[y],d[x]+w[i])//松弛
}
时间复杂度为n*m当然可以优化,下面给出本题题目;
题目链接:http://poj.org/problem?id=3259
题意(这个是copy的。。)
农夫约翰在探索他的许多农场,发现了一些惊人的虫洞。虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1..N,之间有M(1≤M≤2500)条路径,W(1≤W≤200)个虫洞。FJ作为一个狂热的时间旅行的爱好者,他要做到以下几点:开始在一个区域,通过一些路径和虫洞旅行,他要回到最开时出发的那个区域出发前的时间。也许他就能遇到自己了:)。为了帮助FJ找出这是否是可以或不可以,他会为你提供F个农场的完整的映射到(1≤F≤5)。所有的路径所花时间都不大于10000秒,所有的虫洞都不大于万秒的时间回溯。
题目要求:求有无负环,任意点有负环则最终时间能小于开始时间(一直走负环就可以了),下面给出用FIFO队列(SPFA算法)(最坏的情况时间复杂度为n*m,发现负环及时退出)的代码:
#include<iostream>
#include<vector>
#include<queue>
#include<cstdio>
using namespace std;
struct E{
int to, dist;
E() {};
E(int to, int dist) : to(to), dist(dist){};//构造
};
int N,M,W;
vector<vector<E> >G;//邻接表
vector<int> dis;//每个点的最短距离
vector<bool> bUsed;//用bool数组记录每个点是否在队列中
//vector<int> q; //这个是最短路径中的一条弧,本题不用,但是还是写下。
vector<int>cnt;//每个点进入队列的次数
const int INF = 2e9;//无穷大
bool BF(int s){//Ballman_Ford
queue<int> Q;//队列优化
cnt.clear(), cnt.resize(N+1,0);//初始化
dis.clear(), dis.resize(N+1,INF);
//q.clear(),q.resize(N+1,INF);
bUsed.clear(), bUsed.resize(N+1, false);
dis[s]=0,bUsed[s] = true, Q.push(s);//带入起始点
while(! Q.empty()){//用队列来代替n-1次的循环检查
int u = Q.front(); Q.pop();//队列首,也就是上个邻接的点
bUsed[u] = false;//因为存在负权,所以要再次判断
for(int i = 0; i <G [u].size(); i ++){//此点的每个邻接点
E e= G [u][i];
if(dis[u] < INF && dis[e.to] > dis[u] + e.dist){//若接上比原路径要小
dis[e.to] = dis[u] + e.dist;
// q[u]=e.to;
if(! bUsed[e.to]){//若下个点此次还没走过
Q.push(e.to), bUsed[e.to] = true;//将下个点入队
if(++ cnt[e.to] >= N)//如果一个点入队的次数大于等于n,则必有负环
return true;//本题需要有负环
}
}
}
}
return false;
}
int main(){
int F;
scanf("%d",&F);
while(F--){//构造图
scanf("%d%d%d", &N, &M, &W);
G.clear(), G.resize(N+1);
while(M --){
int s, e, t;
scanf("%d%d%d",&s, &e, &t);
G[s].push_back(E(e,t));
G[e].push_back(E(s,t));
}
while(W --){
int s,e,t;
scanf("%d%d%d",&s, &e, &t);
t *= -1;
G[s].push_back(E(e,t));
}
if( BF(1) ) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
最后:
programming is the most fun you can have with your clothes on.