2/1 最短路径和链式前向星的结合应用
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2/1 最短路径和链式前向星的结合应用相关的知识,希望对你有一定的参考价值。
首先写第三点,我觉得是最重要的,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;
以上是关于2/1 最短路径和链式前向星的结合应用的主要内容,如果未能解决你的问题,请参考以下文章