首先写第三点,我觉得是最重要的,dijkstra算法的优化,从复杂度O(n方)复杂度降到
算是最佳的最短路径方法,非常稳定。下面是代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=200005;
typedef long long ll;
const int inf=0x7fffffff;
struct node
{
int to,dis,nxt;
}e[1000005];
int head[maxn],n,m,s,t,u,v,w,nxt,cnt;
ll dist[maxn],minn;
bool vis[maxn];
void add_edge(int from,int to,int dis)
{
e[++cnt].to=to;
e[cnt].dis=dis;
e[cnt].nxt=head[from];
head[from]=cnt;
}
struct node1
{
int dis,pos;
bool operator <(const node1 &x)const
{
return x.dis<dis;
}
};
std::priority_queue<node1>q;
void dijkstra()
{
dist[s]=0;
q.push((node1){0,s}); //到该点的距离为0,位置为点s
while(!q.empty())
{
node1 cur=q.top();
q.pop();
int x=cur.pos,d=cur.dis;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int y=e[i].to;
if(dist[y]>dist[x]+e[i].dis)
{
dist[y]=dist[x]+e[i].dis;
if(!vis[y])
{
q.push((node1){dist[y],y});
}
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
head[0]=-1;
for(int i=1;i<=n;i++)
{
dist[i]=inf;
head[i]=-1;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
dijkstra();
for(int i=1;i<=n;i++)
printf("%lld ",dist[i]);
printf("\n");
return 0;
}
1.给一个dijkstra算法的基本模板(大多数不适用,因为数据范围太大,超过10000那么二维数组就会超出范围,因此要使用链式前向星的方法,使用范围很小)
https://www.luogu.com.cn/problem/P1339
#include <bits/stdc++.h>
using namespace std;
const int maxn=2505;
const int inf=0x7fffffff;
int dist[maxn],mp[2*maxn][2*maxn],minn,n,m,s,t,u,v,w,nxt;
bool vis[maxn];
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=n;i++)
{
dist[i]=inf;
for(int j=1;j<=n;j++)
mp[i][j]=inf;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
mp[u][v]=min(mp[u][v],w);
mp[v][u]=mp[u][v];
}
dist[s]=0;
vis[s]=1;
while(s!=t)
{
minn=inf;
for(int i=1;i<=n;i++)
{
if(mp[s][i]!=inf)
{
dist[i]=min(dist[i],mp[s][i]+dist[s]);
}
if(!vis[i]&&dist[i]<minn)
{
nxt=i;
minn=dist[i];
}
}
if(minn==inf) break;
s=nxt;vis[s]=1;
}
printf("%d\n",dist[t]);
return 0;
}
2.最短路径和链式前向星的结合应用,模板的修改
https://www.luogu.com.cn/problem/P3371
//每次是对于一条链进行操作,因此不能像模板那样一层层处理,不对,也是一层层处理,只是连了起来
#include <bits/stdc++.h>
using namespace std;
const int maxn=20005;
typedef long long ll;
const int inf=0x7fffffff;
struct node
{
int to,dis,nxt;
}e[1000005];
int head[maxn],n,m,s,t,u,v,w,nxt,cnt;
ll dist[maxn],minn;
bool vis[maxn];
void add_edge(int from,int to,int dis)
{
e[++cnt].to=to;
e[cnt].dis=dis;
e[cnt].nxt=head[from];
head[from]=cnt;
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
head[0]=-1;
for(int i=1;i<=n;i++)
{
dist[i]=inf;
head[i]=-1;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
dist[s]=0;
while(!vis[s])
{
vis[s]=1;
minn=inf;
for(int i=head[s];i!=-1;i=e[i].nxt) //每次是对于一条链进行操作,因此不能像模板那样一层层处理
{
if(dist[e[i].to]>e[i].dis+dist[s]&&!vis[e[i].to])
{
dist[e[i].to]=e[i].dis+dist[s];
}
}
for(int i=1;i<=n;i++)
{
if(!vis[i]&&minn>dist[i])
{
minn=dist[i];
s=i;
}
}
}
for(int i=1;i<=n;i++)
printf("%lld ",dist[i]);
printf("\n");
return 0;
}
3.从1开始到各点的最短路径+各个点到1的最短路径之和要最小:
处理方案:
从1开始到各点的最短路径没什么好说的;
各个点到1的最短路径之和要最小:需要反向存图,在用dijkstra算法从1到各点的累加和,跑两遍算法,可举几个例子加深理解,都是符合的
https://www.luogu.com.cn/problem/P1342
巧妙应用函数传递,注意全局变量和数组的清零。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1000005;
typedef long long ll;
const int inf=0x7fffffff;
struct node
{
int to,dis,nxt;
}e[maxn],e1[maxn];
int head[maxn],n,m,s,t,u,v,w,nxt,cnt,cnt1,head1[maxn];
ll dist[maxn],minn,ans,dist1[maxn];
bool vis[maxn];
void add_edge(int from,int to,int dis)
{
e[++cnt].to=to;
e[cnt].dis=dis;
e[cnt].nxt=head[from];
head[from]=cnt;
}
void add_edge1(int from,int to,int dis)
{
e1[++cnt1].to=to;
e1[cnt1].dis=dis;
e1[cnt1].nxt=head1[from];
head1[from]=cnt1;
}
struct node1
{
int dis,pos;
bool operator <(const node1 &x)const
{
return x.dis<dis;
}
};
std::priority_queue<node1>q;
void dijkstra(ll dist[],node e[],int head[])
{
dist[s]=0;
q.push((node1){0,s}); //到该点的距离为0,位置为点s
while(!q.empty())
{
node1 cur=q.top();
q.pop();
int x=cur.pos,d=cur.dis;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int y=e[i].to;
if(dist[y]>dist[x]+e[i].dis)
{
dist[y]=dist[x]+e[i].dis;
if(!vis[y])
{
q.push((node1){dist[y],y});
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
head[0]=-1;head1[0]=-1;
for(int i=1;i<=n;i++)
{
dist[i]=inf;
dist1[i]=inf;
head[i]=-1;
head1[i]=-1;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge1(v,u,w);
}
s=1;
dijkstra(dist,e,head);
memset(vis,0,sizeof(vis));
s=1;
dijkstra(dist1,e1,head1);
for(int i=1;i<=n;i++)
ans+=dist1[i],ans+=dist[i];
printf("%lld\n",ans);
return 0;
}