洛谷 P2446 分析(别看)
2026-10-04 17:20:41
发布于:天津
1 题目
1.1 题目所需求出内容
对于本题,最终要求:一个最小值
1.2 题目背景、允许、禁止与限制
背景:
有 个城市 条单向道路,每条道路有个通过时间
你初始在 号城市,你需要摧毁 号城市
允许:
你有无限多个自爆机器人,每到一个城市,你可以自由选择使这个城市被自爆机器人摧毁或机器人继续行走
求摧毁 号城市的最短时间
限制:
部分城市可能有结界保护,需要摧毁其对应的所有结界才能进入此城市
1.3 题目数据范围与猜测
1.4 一句话概括题意
有向图带权图,从 号点释放若干个机器人,走到 ,每个机器人每个点有两种选择,分别是摧毁(不耗费时间)或移动至另一个相邻点(耗费时间为该边),部分点有限制,即需要摧毁其他若干点才能进入该点
2 题目破题推导
2.1 第一步:限制思维
我们考虑这张图上与普通行走不同的限制
也就是真实进入时间其实是到达该点时间和该点开启时间之间取较大值
3 模型匹配
比较简单,在原来dijkstra模版上改一改即可
要加入一个数组专门用于记录每个点的打开状态
dis数组也要实时取max
此外,节点的打开用到了类似拓扑排序的思维,也就是用一个数组记录限制点数量,对于所有该点取消限制能解锁的点,都要加入小根堆中
4 最终代码(禁止抄袭,仅用于参考)
#include <bits/stdc++.h>
using namespace std;
inline int read(){
int num = 0;
int f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-'){
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
num = (num << 3) + (num << 1) + (ch ^ 48);
ch = getchar();
}
return num * f;
}
int n, m;
const int N = 3e3 + 10;
struct edge{
int to;
int w;
bool operator<(const edge &other) const{
return to < other.to;
}
bool operator==(const edge &other) const{
return to == other.to;
}
};
vector<edge> g[N];
vector<int> jj[N];
bool vis[N];
int dis[N], open[N];
const int INF = 0x3f3f3f3f;
int in[N];
void zdl(){
memset(dis, 0x3f, sizeof(dis));
dis[1] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
q.push({0, 1});
while(!q.empty()){
pair<int, int> f = q.top();
q.pop();
int u = f.second, d = max(dis[u], open[u]);
if (vis[u]) continue;
vis[u] = true;
for (edge now : g[u]){
int v = now.to;
if (dis[v] > d + now.w){
dis[v] = d + now.w;
if (in[v] == 0){
q.push({max(dis[v], open[v]), v});
}
}
}
for (int v : jj[u]){
in[v]--;
open[v] = max(open[v], d);//
if (in[v] == 0){//
q.push({max(dis[v], open[v]), v});//
}
}
}
}
int main(){
n = read(), m = read();
for (int i = 1;i <= m;i++){
int u, v, w;
u = read(), v = read(), w = read();
if (u == v) continue;
g[u].push_back({v, w});
}
for (int i = 1;i <= n;i++){
in[i] = read();
for (int j = 1;j <= in[i];j++){
int li;
li = read();
jj[li].push_back(i);
}
}
zdl();
printf("%d", max(dis[n], open[n]));
return 0;
}
错误点:
dijkstra中应为
dis[v] = d + now.w;
即原到达该点所需最短时间变为该点开启时间与到达时间的较大值(d)+从上一个点到达该点时间(边权)
而非
dis[v] = d + f.first;
因为f里是用于优化dijkstra的小根堆,其中.first代表源点到该点最短路,而非边权
同时要注意.first一定是源点到该点最短路,second一定是点的编号,因为pair默认按第一关键字排序,而选择小跟堆正是希望按第一关键字(first--源点到该点最短路)的最小值更新
这里空空如也















有帮助,赞一个