牛客小白月赛102-D-最短?路径 · znzryb
## 题目大意
给定一个图,边有权值。在节点上每经过 k 条边必须休息一次(或者说每走 k 步必须停顿)。求从起点到终点的最短时间(或路径权值和),考虑休息带来的限制/代价。
## AC代码
参考了官方题解思路,就是在分层图上跑最短路

相比于TLE代码,只加了个这个优化
`while(!q.empty() && dist[n+1]==INF)`
如果dist[n+1]已经确定,那就不用再跑了。
然后代码实现上有比较多的细节,主要是在初始化方面,比如说vis[i][0]也要清理什么的
```cpp
// https://ac.nowcoder.com/acm/contest/91355/D
#include <iostream>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const ll N=2e5+10,INF=1e18+7;
ll T,n,m,k,a[N],u,v,dist[N];
vector<ll> e[N];
bool vis[N][11];
struct edge {
ll node,dis,nrest; // nrest 为多久没休息了
};
struct cmp {
bool operator()(edge a,edge b) {
if(a.dis!=b.dis)
return a.dis>b.dis;
return a.node<b.node;
}
};
priority_queue<edge,vector<edge>,cmp > q;
edge make_edge(ll node,ll dis,ll nrest) {
edge temp;
temp.node=node;temp.dis=dis;temp.nrest=nrest;
return temp;
}
void dijkstra(int t) {
q.push(make_edge(1,0,0));
while(!q.empty() && dist[n+1]==INF) {
ll node=q.top().node,dis=q.top().dis,nrest=q.top().nrest;
q.pop();
if(vis[node][nrest]) // 之前访问过,弹出
continue;
vis[node][nrest]=true;
dist[node]=min(dis,dist[node]);
for(int i=0;i<e[node].size();i++) {
if(nrest>=k)
q.push(make_edge(e[node][i],dis+a[node],0));
else {
q.push(make_edge(e[node][i],dis+a[node],0));
q.push(make_edge(e[node][i],dis+1,nrest+1));
}
}
}
}
void clear() {
priority_queue<edge,vector<edge>,cmp > empty;
swap(empty,q);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>T;
for(int _=1;_<=T;_++) {
cin>>n>>m>>k;
clear();
for(int i=1;i<=n+1;i++)
e[i].clear();
for(int i=1;i<=n;i++) {
cin>>a[i];
}
fill(&dist[1],&dist[n+2],INF);
for(int i=1;i<=n+1;i++)
for(int j=0;j<=k;j++)
vis[i][j]=false;
for(int i=1;i<=m;i++) {
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
e[n].push_back(n+1);
e[n+1].push_back(n);
dijkstra(_);
cout<<dist[n+1]<<endl;
}
return 0;
}
// TLE https://ac.nowcoder.com/acm/contest/view-submission?submissionId=72128029
// AC https://ac.nowcoder.com/acm/contest/view-submission?submissionId=72128343
```
## 心路历程(WA,TLE,MLE……)
过了40% TLE [https://ac.nowcoder.com/acm/contest/view-submission?submissionId=72128029](https://ac.nowcoder.com/acm/contest/view-submission?submissionId=72128029)
```cpp
// https://ac.nowcoder.com/acm/contest/91355/D
#include <iostream>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const ll N=2e5+10,INF=1e18+7;
ll T,n,m,k,a[N],u,v,dist[N];
vector<ll> e[N];
bool vis[N][11];
struct edge {
ll node,dis,nrest; // nrest 为多久没休息了
};
struct cmp {
bool operator()(edge a,edge b) {
if(a.dis!=b.dis)
return a.dis>b.dis;
return a.node<b.node;
}
};
priority_queue<edge,vector<edge>,cmp > q;
edge make_edge(ll node,ll dis,ll nrest) {
edge temp;
temp.node=node;temp.dis=dis;temp.nrest=nrest;
return temp;
}
void dijkstra(int t) {
q.push(make_edge(1,0,0));
while(!q.empty()) {
ll node=q.top().node,dis=q.top().dis,nrest=q.top().nrest;
q.pop();
if(vis[node][nrest]) // 之前访问过,弹出
continue;
vis[node][nrest]=true;
dist[node]=min(dis,dist[node]);
for(int i=0;i<e[node].size();i++) {
if(nrest>=k)
q.push(make_edge(e[node][i],dis+a[node],0));
else {
q.push(make_edge(e[node][i],dis+a[node],0));
q.push(make_edge(e[node][i],dis+1,nrest+1));
}
}
}
}
void clear() {
priority_queue<edge,vector<edge>,cmp > empty;
swap(empty,q);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>T;
for(int _=1;_<=T;_++) {
cin>>n>>m>>k;
clear();
for(int i=1;i<=n+1;i++)
e[i].clear();
for(int i=1;i<=n;i++) {
cin>>a[i];
}
fill(&dist[1],&dist[n+2],INF);
for(int i=1;i<=n+1;i++)
for(int j=0;j<=k;j++)
vis[i][j]=false;
for(int i=1;i<=m;i++) {
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
e[n].push_back(n+1);
e[n+1].push_back(n);
dijkstra(_);
cout<<dist[n+1]<<endl;
}
return 0;
}
// TLE https://ac.nowcoder.com/acm/contest/view-submission?submissionId=72128029
```