#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <string>
#include <map>
using namespace std;
const int N = 10005;
const int inf=0x3f3f3f3f;
struct Node{
int u,len;
};int dist[N];int vis[2000];
bool operator < (Node a,Node b){
return a.len > b.len;
}
struct Edge{
int v,w,next;
}edge[N*N];
int head[N];
int tot;
void init(){
memset(head,-1,sizeof(head));
tot = 0;
}
void addEdge(int u,int v,int w,int &k){
edge[k].v = v,edge[k].w = w,edge[k].next = head[u];
head[u] = k++;
}
void dijkstra(int start,int n){
memset(vis,0,sizeof(vis));
priority_queue <Node > q;
Node s;
for(int i=1;i<=n;i++)dist[i]=inf;dist[start]=0;vis[start]=1;
s.u = start,s.len = 0;
q.push(s);
while(!q.empty()){
Node now = q.top();
q.pop();int u=now.u;int d=now.len;
if(d>dist[u])continue;
//if(vis[u])continue;
//vis[u]=1;
for(int k=head[now.u];k!=-1;k=edge[k].next){
if(dist[u]+edge[k].w<dist[edge[k].v])
{
dist[edge[k].v]=dist[u]+edge[k].w;
Node npw;npw.u=edge[k].v,npw.len=dist[edge[k].v];
q.push(npw);
}
}
}
}
int main()
{
init();int n,m;
cin>>m>>n;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
addEdge(u,v,w,tot);
addEdge(v,u,w,tot);
}
dijkstra(1,n);
printf("%d\n",dist[n]);
return 0;
}
dijkstra算法
适用于权值为正,有/无重边的有向/无向图
struct headnode
{
long long d;
int u;
bool operator < (const headnode &a) const
{
return d>a.d;
}
headnode(long long x,int y):d(x),u(y){};
};
void dijkstra()
{
for(int i=1;i<=n;++i)
{
d[i]=inf;
p[i].clear();
}
d[1]=0;
priority_queue<headnode>p1;
p1.push((headnode){0,1});
while(!p1.empty())
{
headnode now=p1.top();
p1.pop();
if(now.d!=d[now.u])
continue;
for(int i=0;i<g[now.u].size();++i)
{
node &e1=edge[g[now.u][i]];
if(d[e1.t]>d[now.u]+e1.v)
{
d[e1.t]=d[now.u]+e1.v;
p[e1.t].clear();
p[e1.t].push_back(g[now.u][i]); //存入到达点e1.t的边的编号
p1.push((headnode){d[e1.t],e1.t});
}
else if(d[e1.t]==d[now.u]+e1.v)
{
p[e1.t].push_back(g[now.u][i]); //存入到达点e1.t的边的编号
}
}
}
}
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int d[512][512];
int vis[512];
int dijkstra(int n)// O(n^2)
{
memset(vis,-1,sizeof(vis));
for(int i=0;i<n;++i)
{
int s,k=0x3f3f3f3f;
for(int j=2;j<=n;++j)
{
if(k>d[1][j]&&vis[j]==-1)
{k=d[1][j];s=j;}
}
vis[s]=0;
for(int j=1;j<=n;++j)
{
if(d[1][j]>d[1][s]+d[s][j])
d[1][j]=d[1][s]+d[s][j];
}
}
if(d[1][n]==0x3f3f3f3f)
return -1;
else
return d[1][n];
}
int main()
{
int n,m;cin>>n>>m;
memset(d,0x3f,sizeof(d));
for(int i=1;i<=n;++i)d[i][i]=0;
while(m--)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
if(d[a][b]>c)d[a][b]=c;
}
cout<<dijkstra(n)<<endl;
return 0;
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int N=150000+10,inf=0x3f3f3f3f;
int h[N],nex[N],to[N],w[N],con=1;
typedef pair<int,int>pii;
int d[N],vis[N];
int dijkstra(int n)//O(mlog(m))
{
priority_queue<pii,vector<pii>,greater<pii> >q;
memset(d,0x3f,sizeof(d));
d[1]=0;
q.push(pii(0,1));
while(!q.empty())
{
pii now=q.top();q.pop();
if(vis[now.second])
continue;
vis[now.second]=1;
d[now.second]=now.first;
for(int i=h[now.second];i;i=nex[i])
{
if(d[to[i]]>(d[now.second]+w[i]))
{
d[to[i]]=d[now.second]+w[i];
q.push(pii(d[to[i]],to[i]));
}
}
}
if(d[n]==inf)
return -1;
else
return d[n];
}
int main()
{
//freopen("1.txt","r",stdin);
int n,m;cin>>n>>m;
while(m--)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
if(a==b)continue;
to[con]=b;w[con]=c;
nex[con]=h[a];
h[a]=con++;
}
cout<<dijkstra(n)<<endl;
return 0;
}
Bellman-ford算法求边数限制的带负权最短路O(nm)
可以解决带负环问题,边数限制问题
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=512+10;
struct node
{
int c,t,v;
node(int x=0,int y=0,int z=0):c(x),t(y),v(z){}
}edge[10010];
int d[N],b[N],con=0;
void BF(int n,int k)//求不超过k条边的带负权最短路
{
for(int i=0;i<k;++i)//保证不超过k条边 O(nm)
{
memcpy(b,d,sizeof(b));
for(int j=0;j<con;++j)
{
node e=edge[j];
if(b[e.c]==0x3f3f3f3f)
continue;
if(d[e.t]>b[e.c]+e.v)
d[e.t]=b[e.c]+e.v;
}
}
if(d[n]==0x3f3f3f3f)
cout<<"impossible"<<endl;
else
cout<<d[n]<<endl;
}
int main()
{
// freopen("1.txt","r",stdin);
int n,m,k;
cin>>n>>m>>k;
memset(d,0x3f,sizeof(d));
d[1]=0;
while(m--)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
edge[con]=node(a,b,c);con++;
}
BF(n,k);
return 0;
}
spfa求带负权最短路一般O(m),最坏O(nm)
可求带负环,带负环图用stack代替queue速度更快
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;
int h[N],nex[N],to[N],con=1,v[N];
int d[N];
bool vis[N];
void spfa(int n)
{
memset(d,0x3f,sizeof(d));//求无负环的最短路
d[1]=0;
queue<int>q;
q.push(1);
vis[1]=1;
while(!q.empty())
{
int now=q.front();q.pop();
vis[now]=0;
for(int i=h[now];i;i=nex[i])
{
if(d[to[i]]>d[now]+v[i])
{
d[to[i]]=d[now]+v[i];
if(!vis[to[i]])
{q.push(to[i]);
vis[to[i]]=1;}
}
}
}
if(d[n]==inf)
cout<<"impossible"<<endl;
else
cout<<d[n]<<endl;
}
int main()
{
int n,m;cin>>n>>m;
while(m--)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
nex[con]=h[a];
h[a]=con;
to[con]=b;v[con++]=c;
}
spfa(n);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=2000+10,M=1e4+10,inf=0x3f3f3f3f;
int h[N],nex[M],to[M],v[M],con=1;
int cnt[N],vis[N],d[N];
void spfa(int n)//判断是否有负环
{
memset(d,0x3f,sizeof(d));
d[1]=0;
queue<int>q;
for(int i=1;i<=n;++i)
{
q.push(i);
vis[i]=1;
}
while(!q.empty())
{
int now=q.front();q.pop();
vis[now]=0;
for(int i=h[now];i;i=nex[i])
{
if(d[to[i]]>d[now]+v[i])
{
d[to[i]]=d[now]+v[i];
cnt[to[i]]=cnt[now]+1;
if(cnt[to[i]]==n)
{
cout<<"Yes"<<endl;
return;
}
if(!vis[to[i]])
{q.push(to[i]);
vis[to[i]]=1;
}
}
}
}
cout<<"No"<<endl;
return;
}
int main()
{
int n,m;cin>>n>>m;
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
nex[con]=h[a];
h[a]=con;
to[con]=b;
v[con]=c;con++;
}
spfa(n);
return 0;
}
floyd求多源最短路,不能有负环,可有负权边O(n^3)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
int d[256][256];
void floyd(int n)
{
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
if(d[i][k]==inf||d[k][j]==inf)
continue;
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
int main()
{
int n,m,k;cin>>n>>m>>k;
memset(d,0x3f,sizeof(d));
for(int i=1;i<=n;++i)
d[i][i]=0;
while(m--)
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
d[a][b]=min(d[a][b],c);
}
floyd(n);
while(k--)
{
int a,b;scanf("%d%d",&a,&b);
if(d[a][b]==inf)
cout<<"impossible"<<endl;
else
cout<<d[a][b]<<endl;
}
return 0;
}