直接上代码?
#include<bits/stdc++.h> #define eps 1e-8 using namespace std; int head[10005],cnt=-1,v[10005],rt[10005],mark[1000005],ans,fa[10005]; int n,m,tot; double se,dis[10100]; priority_queue<pair<double,int > >q;//这里注意,是double ,int struct Heap{ int ls,rs,dist,to;//左儿子 右儿子 左偏树内点的dist,每个点对应边的终点 double w;//小根堆每个点的权值 }tr[30000010]; struct node{ int next,to; double w; }e[10000010]; void add(int from,int to,double w){ e[++cnt].next=head[from]; e[cnt].to=to; e[cnt].w=w; head[from]=cnt; } int merge(int x,int y){ if(!x||!y)return x+y; if(tr[x].w-tr[y].w>=eps)swap(x,y); int p=++tot; tr[p]=tr[x]; tr[p].rs=merge(tr[p].rs,y); if(tr[tr[p].ls].dist<tr[tr[p].rs].dist)swap(tr[p].ls,tr[p].rs); tr[p].dist=tr[tr[x].rs].dist+1; return p; } void dijkstra(){ memset(v,0,sizeof v); memset(dis,127,sizeof dis); dis[n]=0; q.push(make_pair(0,n)); while(!q.empty()){ int from=q.top().second; q.pop(); if(v[from])continue; v[from]=1; for(int i=head[from];~i;i=e[i].next){ if(i&1){//反向边 int to=e[i].to; if(dis[to]-(dis[from]+e[i].w)>eps){ dis[to]=dis[from]+e[i].w; q.push(make_pair(-dis[to],to)); } } } } }//djk跑一遍从终点反向往回走的最短路树 void dfs(int from){ v[from]=1; for(int i=head[from];i!=-1;i=e[i].next){ int to=e[i].to; if(i&1){ if(v[to])continue; if(fabs(dis[from]+e[i].w-dis[to])<eps){ fa[to]=from; mark[i^1]=1; dfs(to); } } } }//标记一下最短路树上有哪些边 int newnode(double w,int to){ int x=++tot; tr[x].w=w; tr[x].dist=1; tr[x].to=to; return x; } int main(){ memset(head,-1,sizeof head); scanf("%d%d%lf",&n,&m,&se); for(int i=1;i<=m;i++){ int x,y; double z; scanf("%d%d%lf",&x,&y,&z); add(x,y,z); add(y,x,z); } dijkstra(); memset(v,0,sizeof v); dfs(n); for(int i=0;i<=cnt;i+=2){ if(!mark[i]){ int from=e[i^1].to,to=e[i].to; if(dis[from]==dis[0]||dis[to]==dis[0])continue; rt[from]=merge(rt[from],newnode(dis[to]+e[i].w-dis[from],to)); } }//把不在最短路树上的路径加入堆; //权值是"走不在最短路树上的边的路径长度与最短路的路径长度的差值" for(int i=1;i<=n;i++){ q.push(make_pair(-dis[i],i)); } for(int i=1;i<=n;i++){ int from=q.top().second; q.pop(); if(fa[from])rt[from]=merge(rt[from],rt[fa[from]]); }//把在最短路树上的路径加入堆 if(dis[1]-se<eps)se-=dis[1],ans++; //走最短路的情况 if(rt[1])q.push(make_pair(-tr[rt[1]].w,rt[1]));//假如rt[1]没有说明从n根本到不了1 while(!q.empty()){ int from=q.top().second; double cur=q.top().first; double w=dis[1]-cur;//当前路径的长度 if(w-se>=eps)break;//能量耗完 q.pop(); se-=w; ans++;//找到一条k路径 for(int i=0;i<2;i++){//加当前的堆的路径 int to=i?tr[from].rs:tr[from].ls; if(to)q.push(make_pair(cur+tr[from].w-tr[to].w,to));//一条新的路径 加入优先队列 }//把左儿子和右儿子加入优先队列,因为是小根堆 ,所以这样加肯定是从小到大的; if(rt[tr[from].to])q.push(make_pair(cur-tr[rt[tr[from].to]].w,rt[tr[from].to])); //加to对应的新的堆的路径; } printf("%d\n",ans); }