[NC22594]Rinne Loves Graph
一、题目
二、思路
这题的题意很明显,就是在走到的点如果是有看守的点,那么从这个点走到下个点的时候k就要+1,求经过的看守点不超过k次的最短路径
这题一看到就能想到要用分层图来写,因为有个类似天数的限制,然后看了题解后发现也能用最短路dp来做,但是最短路dp我还没学明白,等以后有机会再回来补充下这题的最短路dp的写法
建图的过程就是如果当前点是看守点,那么就要和下一层的下一个点来连接,反之亦然,如果当前点不是看守点,那直接在当前层和下一个点连边即可
连边的时候注意一下层的范围限制,详细看代码
三、代码
#include<bits/stdc++.h>
using namespace std;
const int N = 10010 * 10; //因为是分层图,记得乘层数
typedef pair<int, int> PII;
int n, m, k;
int h[N], e[N], ne[N], w[N], idx;
int dist[N];
bool st[N];
int f[N];
void add(int a, int b, int c){
w[idx] = c;
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
void dijkstra(){ //堆优化版的dijkstra板子
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII> > heap;
heap.push({0, 1});
while(heap.size()){
PII k = heap.top();
heap.pop();
int ver = k.second, distance = k.first;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver]; i != -1; i = ne[i]){
int j = e[i];
if(dist[j] > distance + w[i]){
dist[j] = distance + w[i];
heap.push({dist[j], j});
}
}
}
}
int main(){
cin >> n >> m >> k;
memset(h, -1, sizeof h);
for(int i = 1; i <= n; i ++){
int t;
cin >> t;
f[i] = t;
}
int u, v, w;
for(int i = 1 ; i <= m; i ++){
cin >> u >> v >> w;
if(!f[u]){ //这里是当前点不是看守点的时候,每层直接连边即可
for(int j = 0; j <= k; j ++) add(u + j * n, v + j * n, w);
}
if(!f[v]){
for(int j = 0; j <= k; j ++) add(v + j * n, u + j * n, w);
}
if(f[u]){ //这里是当前点为看守点的时候,要和下一层的下一个点连边,注意j的范围是0 ~ k - 1, 因为下一个点最大可以到j + 1层
for(int j = 0; j < k; j ++) add(u + j * n, v + (j + 1) * n, w);
}
if(f[v]){
for(int j = 0; j < k; j ++) add(v + j * n, u + (j + 1) * n, w);
}
}
dijkstra();
int ans = 0x3f3f3f3f; //这里要记得别打0x3f。。。我memset的时候打习惯了,要打0x3f3f3f3f,不然会wa
for(int i = 1; i <= k + 1; i ++){
ans = min(ans, dist[i * n]); //n的取值范围是第1层的n一直到第k + 1层的n
}
if(ans == 0x3f3f3f3f) cout << "-1" << endl;
else cout << ans << endl;
return 0;
}


浙公网安备 33010602011771号