题目链接http://acm.hdu.edu.cn/showproblem.php?pid=6705
题意
给出一张图,每条边可以走任意多次,问所有路径的第k短。
题解
介绍一个乱做的方法。
首先如果直接跑最短路会MLE(以及TLE),但很明显跑最短路的时候很多权值太大的是不需要的。
所以我就二分了一个权值mid,如果跑出来的权值大于mid,我就不要。这样如果最短路队列里面有k个,就把二分的上界缩小,否则下界变大。
二分出界限后,再跑最短路就行了。
这样复杂度是
n
l
o
g
2
n
nlog^2n
nlog2n的,二分一个
l
o
g
log
log,最短路一个
l
o
g
log
log,会TLE。
但观察一下就可以发现,二分的判断其实不需要用到优先队列,只用普通的队列就行了,因为它只需要判断是否有k个。
这样复杂度就降成了
n
l
o
g
nlog
nlog级别。
最后加个剪枝,给边排个序,如果已经大于了就break掉,这样就可以过了。
正常做法应该是用multiset维护大小为k的堆,每次从后面删。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
const ll inf=1e14;
int T,n,m,qn;
struct Edge{
int v,w;
bool operator<(const Edge k)const{
return w<k.w;
}
};
vector<Edge>e[N];
int qq[N];
ll ans[N];
struct Node{
int pos;
ll val;
bool operator<(const Node k)const{
return val>k.val;
}
};
int mx;
queue<Node>q;
inline bool ck(const ll mid){
while(!q.empty()) q.pop();
for(int i=1;i<=n;i++){q.push((Node){i,0});}
int cnt=0;
while(!q.empty()){
Node t=q.front();q.pop();
int u=t.pos;
for(int i=0;i<e[u].size();i++){
Edge vv=e[u][i];
if(0ll+t.val+vv.w>mid) break;
cnt++;
if(cnt>=mx) return true;
q.push((Node){vv.v,0ll+t.val+vv.w});
}
}
return false;
}
priority_queue<Node>qqq;
inline int dij(const ll mid){
int tot=0;
while(!qqq.empty()) qqq.pop();
for(int i=1;i<=n;i++){qqq.push((Node){i,0});}
while(!qqq.empty()){
Node t=qqq.top();qqq.pop();
int u=t.pos;
if(t.val>0ll) ans[++tot]=0ll+t.val;
if(tot>=mx) break;
for(int i=0;i<e[u].size();i++){
Edge vv=e[u][i];
if(0ll+t.val+vv.w>mid) break;
qqq.push((Node){vv.v,0ll+t.val+vv.w});
}
}
return false;
}
int main()
{
// freopen("in.in","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&qn);
for(int i=1;i<=n;i++) e[i].clear();
for(int i=1,u,v,w;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
e[u].push_back((Edge){v,w});
}
for(int i=1;i<=n;i++){
sort(e[i].begin(),e[i].end());
}
mx=0;
for(int i=1;i<=qn;i++){
scanf("%d",&qq[i]);
mx=max(mx,qq[i]);
}
ll lo=0,hi=inf,nd=0;
while(lo<=hi){
ll mid=lo+hi>>1;
if(ck(mid)) nd=mid,hi=mid-1;
else lo=mid+1;
}
dij(nd);
for(int i=1;i<=qn;i++){
printf("%lld\n",ans[qq[i]]);
}
}
}