1.bellman-flod算法—O(nm) 第一重是点,迭代k次的话是指,从1 开始最多不经过超过k条边
注意的是要有备份,backup数组,更新的时候用备份的数组更新,每次更新的是所有的边,取最小值,边的存储比较随意
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510,M=10010;
const int INF=0x3f3f3f3f;
int n,m,k;
int dist[N];
int backup[N];//备份
struct Edge{
int a,b,c;
}e[M];//存边的时候比较随意
int bfd(){
dist[1]=0;
//第一重循环的意义--最多经过多少条边
for(int i=0;i<k;i++){
memcpy(backup,dist,sizeof dist);//重要的地方
for(int j=0;j<m;j++){
int a=e[j].a,b=e[j].b,c=e[j].c;
dist[b]=min(dist[b],backup[a]+c);//没有判断,所以也可能没有更新,spfa优化
}
}
if(dist[n]>INF/2) return -1;//为什么是/2,因为就是存在负权边
return dist[n];
}
int main(){
memset(dist,0x3f,sizeof dist);
cin>>n>>m>>k;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
e[i].a =a;
e[i].b =b;
e[i].c =c;
}
int t=bfd();
if(t==-1) cout<<"impossible"<<endl;
else cout<<t<<endl;
return 0;
}
2.spfa 算法—把变小的点放在队列里面,等待更新其他的点
求最短路—,book[N]这里就用来判断是不是在队列里面
每次从队列里拿出一个点,先去更新它的邻边,然后当它的邻边不在队列的时候再入队,顺序不能颠倒
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e5+10;
const int M=1e5+10;
const int INF=0x3f3f3f3f;
int top=0;
int head[N];
int book[N];//这个点是否在队列当中
struct Edge{
int v;
int next=-1;//最好初始化-1
int w;
}e[M];
int n,m;
int dist[N];//距离
void add(int a,int b,int c){
e[top].v=b;
e[top].next=head[a];
e[top].w=c;
head[a]=top++;
}
int spfa(){
dist[1]=0;
queue<int> q;
q.push(1);
book[1]=1;
while(q.size() ){
int t=q.front() ;
q.pop() ;
book[t]=0;//0表示不在
for(int j=head[t];j!=-1;j=e[j].next) {
int tt=e[j].v;
if(dist[tt]>dist[t]+e[j].w ){
dist[tt]=dist[t]+e[j].w;
if(book[tt]==0){
q.push(tt);
book[tt]=1;
}
}
}
}
if(dist[n]==INF) return -1;
return dist[n];
}
int main(){
memset(head,-1,sizeof head);
memset(book,0,sizeof book);
memset(dist,0x3f,sizeof dist);
cin>>n>>m;
while(m--){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
if(spfa()==-1) cout<<"impossible"<<endl;
else cout<<spfa()<<endl;
return 0;
}
判断是否存在负环----
—dist[N]数组记录距离,cnt[N]记录边数,如果边数等于或者超过n,也就是说存在负环了,在循环里面判断如果cnt[tt]==n,直接就返回true了
//因为是要判断是否存在负环,不一定从1 开始出发,所以最开始所有的点都要入队
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e5+10,M=1e5+10;
const int INF=0x3f3f3f3f;
int head[N];
int top=0;
int dist[N];
int book[N]; //在不在队列里面
int cnt[N]; //记录边数
int n,m;
struct edge{
int v;
int next=-1;
int w;
}e[M];
void add(int u,int v,int w){
e[top].v =v;
e[top].next =head[u];
e[top].w =w;
head[u]=top++;
}
//用在队列里面的点去更新它的邻边
int spfa(){
dist[1]=0;//
queue<int> q;
for(int i=1;i<=n;i++){
q.push(i);
}
while(q.size()){
int t=q.front();
q.pop();
book[t]=0;
for(int j=head[t];j!=-1;j=e[j].next ){
int tt=e[j].v ;
if(dist[tt]>dist[t]+e[j].w){
dist[tt]=dist[t]+e[j].w;
cnt[tt]=cnt[t]+1;
if(cnt[tt]==n) return true;
if(book[tt]==0){
q.push(tt);
book[tt]=1;
}
}
}
}
//不一定是cnt[n]啊
// if(cnt[n]>=n) return true;
return false;
}
int main(){
memset(head,-1,sizeof head);
memset(dist,0x3f,sizeof dist);
memset(book,1,sizeof book);
cin>>n>>m;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
if(spfa()) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}