目录
1.Dijkstra求最短路
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。
输入格式
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出格式
输出一个整数,表示 1 号点到 n 号点的最短距离。
如果路径不存在,则输出 −1。
数据范围
1≤n≤500
1≤m≤10^5
图中涉及边长均不超过10000。
输入样例:
3 3
1 2 2
2 3 1
1 3 4
输出样例:
3
代码展示
邻接矩阵法
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int g[N][N];
int dist[N];
bool st[N];
int n,m;
void Dijkstra()
{
memset(dist,0x3f,sizeof(dist));
dist[1]=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
}
st[t]=1;
for(int j=1;j<=n;j++)
dist[j]=min(dist[j],dist[t]+g[t][j]);
}
}
int main()
{
cin>>n>>m;
memset(g,0x3f,sizeof(g));
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
}
Dijkstra();
if(dist[n]!=0x3f3f3f3f)
cout<<dist[n];
else
cout<<-1;
}
链式前向星法
#include<bits/stdc++.h>
using namespace std;
const int N = 510, M = 100010;
struct node{
int e,w,ne;
}edge[M];
int h[M],idx;
bool st[N];
int dist[N];
int n,m;
void add(int a,int b,int c)
{
edge[idx].e=b,edge[idx].w=c,edge[idx].ne=h[a],h[a]=idx++;
}
void Dijkstra()
{
memset(dist,0x3f,sizeof(dist));
dist[1]=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
}
st[t]=1;
for(int j=h[t];j!=-1;j=edge[j].ne)
{
int i=edge[j].e;
dist[i]=min(dist[i],dist[t]+edge[j].w);
}
}
}
int main()
{
memset(h,-1,sizeof(h));
cin>>n>>m;
while(m--)
{
int a,b,w;
cin>>a>>b>>w;
add(a,b,w);
}
Dijkstra();
if(dist[n]!=0x3f3f3f3f)
cout<<dist[n];
else
cout<<-1;
}
链式前向星法(小根堆优化版)
数据范围
1≤n,m≤1.5×10^5
图中涉及边长均不小于 0,且不超过 10000。
数据保证:如果最短路存在,则最短路的长度不超过 10^9。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N = 1e6+10;
struct node{
int e,w,ne;
}edge[N];
int h[N],idx;
bool st[N];
int dist[N];
int n,m;
void add(int a,int b,int c)
{
edge[idx].e=b,edge[idx].w=c,edge[idx].ne=h[a],h[a]=idx++;
}
void Dijkstra()
{
memset(dist,0x3f,sizeof(dist));
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,1});
while(heap.size())
{
auto t=heap.top();
heap.pop();
int ver=t.second,dis=t.first;
if(st[ver])
continue;
st[ver]=1;
for(int j=h[ver];j!=-1;j=edge[j].ne)
{
int i=edge[j].e;
if(dist[i]>dist[ver]+edge[j].w)
{
dist[i]=dist[ver]+edge[j].w;
heap.push({dist[i],i});
}
}
}
}
int main()
{
memset(h,-1,sizeof(h));
cin>>n>>m;
while(m--)
{
int a,b,w;
cin>>a>>b>>w;
add(a,b,w);
}
Dijkstra();
if(dist[n]!=0x3f3f3f3f)
cout<<dist[n];
else
cout<<-1;
}
找到t的耗时从O(n^2)变为O(n),更新dist的耗时从O(m)变为O(m*logn),总时间复杂度从O(n^2)变为O(n+m*logn)...
2.拓扑排序
给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。
请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。
若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。
输入格式
第一行包含两个整数 n 和 m。
接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 (x,y)。
输出格式
共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。
否则输出 −1。
数据范围
1≤n,m≤10^5
输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3
代码展示
链式前向星法
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
struct code{
int e,ne;
}edge[N];
int idx;
int h[N];
int d[N];
queue<int> q;
int n,m;
int ans[N],cnt;
void add(int a,int b)
{
edge[idx].e=b,edge[idx].ne=h[a],h[a]=idx++;
}
void topsort()
{
for(int i=1;i<=n;i++)
{
if(d[i]==0)
q.push(i);
}
while(q.size())
{
int t=q.front();
q.pop();
ans[cnt++]=t;
for(int i=h[t];i!=-1;i=edge[i].ne)
{
int x=edge[i].e;
d[x]--;
if(d[x]==0)
q.push(x);
}
}
if(cnt==n)
for(int i=0;i<cnt;i++)
cout<<ans[i]<<" ";
else
cout<<-1;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof(h));
while(m--)
{
int x,y;
cin>>x>>y;
d[y]++;
add(x,y);
}
topsort();
}
STL法
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
vector<int> h[N];
int d[N];
queue<int> q;
int n,m;
int ans[N],cnt;
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
h[x].push_back(y);
d[y]++;
}
for(int i=1;i<=n;i++)
{
if(!d[i])
q.push(i);
}
while(q.size())
{
int t=q.front();
q.pop();
ans[cnt++]=t;
for(auto x:h[t])
{
d[x]--;
if(d[x]==0)
q.push(x);
}
}
if(cnt==n)
for(int i=0;i<cnt;i++)
cout<<ans[i]<<" ";
else
cout<<-1;
}


被折叠的 条评论
为什么被折叠?



