k短路
1. a* 算法
用优先队列维护目前路径的最小值进行bfs
一个路径的权值定义为已走长度+剩余最短路长度
即带估价函数的bfs
O(nklogk)
2.可持久化可并堆
我们先建出最短路树(即每个节点的父节点为其一条最短路上的后继)
对于一条边,定义其权值为
即走他而非最短路增加的代价
发现对于路径
考虑有一条路径向外扩展,对一条路径,有两种操作可以使其不重不漏地扩展为新路径
1. 替换非树边集中的最后一条边为一条权更大的边
2. 在后边拼上一条边,此边为最后一条边终点在最短路树上祖先所直接连接的非树边
发现任意点备选集合可以由其父亲并上有自己出发的非树边
可持久化可并堆维护
求值时,每次取出最短的,扩展新边
重复
例: P2483 [SDOI2010] 魔法猪学院
#include<bits/stdc++.h>
using namespace std;
const int N = 5010,M = 200010;
struct que
{
int u;
double w;
bool operator < (const que &rhs) const
{
return w>rhs.w;
}
}seq[N];
struct heap
{
int ls,rs,ed,d;
double w;
}hp[20*M];
int tot,n,m,vis[N],h1[N],h2[N];
int fa[N],rt[N],cnte1,cnte2;
double E,dis[N];
int clone(int u)
{
hp[++tot].ls=hp[u].ls;
hp[tot].rs=hp[u].rs;
hp[tot].ed=hp[u].ed;
hp[tot].d=hp[u].d;
hp[tot].w=hp[u].w;
return tot;
}
int init(int ed,double w)
{
hp[++tot]={0,0,ed,0,w};
return tot;
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
if(hp[x].w>hp[y].w) swap(x,y);
int p=clone(x);
hp[p].rs=merge(hp[x].rs,y);
if(hp[hp[p].ls].d<hp[hp[p].rs].d)
swap(hp[p].ls,hp[p].rs);
hp[p].d=hp[hp[p].rs].d;
return p;
}
int cnt;
struct edge
{
int u,v,nxt;
double w;
}e1[M],e2[M];
priority_queue<que>q;
void dijstra()
{
for(int i=1;i<=n;i++) dis[i]=10000000000000;
dis[n]=0;
q.push({n,0});
while(!q.empty())
{
cnt++;
que x=q.top();
q.pop();
if(vis[x.u]) continue;
vis[x.u]=1;
for(int i=h2[x.u];i;i=e2[i].nxt)
{
int v=e2[i].v;
double w=e2[i].w;
if(dis[v]>dis[x.u]+w)
{
dis[v]=dis[x.u]+w;
q.push({v,dis[v]});
}
}
}
return ;
}
int ontr[M],tf[N];
void dfs(int u)
{
cnt++;
tf[u]=1;
for(int i=h2[u];i;i=e2[i].nxt)
{
int v=e2[i].v;
if(!tf[v]&&dis[v]==dis[u]+e2[i].w)
{
fa[v]=u;
ontr[i]=1;
dfs(v);
}
}
return ;
}
void dfs2(int u)
{
cnt++;
tf[u]=1;
if(fa[u]) rt[u]=merge(rt[u],rt[fa[u]]);
for(int i=h2[u];i;i=e2[i].nxt)
if(fa[e2[i].v]==u&&!tf[e2[i].v])
dfs2(e2[i].v);
return ;
}
void add1(int u,int v,double w)
{
e1[++cnte1].u=u;
e1[cnte1].v=v;
e1[cnte1].w=w;
e1[cnte1].nxt=h1[u];
h1[u]=cnte1;
}
int rev[M];
void add2(int u,int v,double w)
{
e2[++cnte2].u=u;
e2[cnte2].v=v;
e2[cnte2].w=w;
e2[cnte2].nxt=h2[u];
h2[u]=cnte2;
}
void input()
{
scanf("%d%d%lf",&n,&m,&E);
for(int i=1;i<=m;i++)
{
int u,v;double w;
scanf("%d%d%lf",&u,&v,&w);
if(u==n) continue;
add1(u,v,w);
add2(v,u,w);
rev[cnte1]=cnte2;
}
return ;
}
int main()
{
// freopen("P2483_1.in","r",stdin);
input();
dijstra();
dfs(n);
for(int i=1;i<=n;i++)
if(vis[i])
for(int j=h1[i];j;j=e1[j].nxt)
if(!ontr[rev[j]])
rt[i]=merge(rt[i],init(e1[j].v,dis[e1[j].v]+e1[j].w-dis[i]));
memset(tf,0,sizeof tf);
dfs2(n);
// for(int i=1;i<=n;i++) cout<<dis[i]<<endl;
int ans=0;
q.push({rt[1],hp[rt[1]].w});
E-=dis[1],ans++;
while(E>0)
{
cnt++;
if(q.empty()) break;
que x=q.top();
q.pop();
if(E-dis[1]-x.w<0) break;
else E-=dis[1]+x.w,ans++;
if(hp[x.u].ls) q.push({hp[x.u].ls,x.w-hp[x.u].w+hp[hp[x.u].ls].w});
if(hp[x.u].rs) q.push({hp[x.u].rs,x.w-hp[x.u].w+hp[hp[x.u].rs].w});
if(rt[hp[x.u].ed]) q.push({rt[hp[x.u].ed],x.w+hp[rt[hp[x.u].ed]].w});
}
cout<<cnt<<endl;
cout<<ans;
// cout<<1.00*tot/M<<" "<<cnte1<<" "<<cnte2<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人