题目:https://www.luogu.org/problem/P2446
Description:
带限制的最短路,途中一些点被其他点限制,当限制该点的点都被到达后方可通过该点。你可以释放无限多个机器人替你跑路。
Solution:
情景一:当前到达的点没有被保护 => 可以直接通过
情景二:当前到达的点被保护,不能通过 => 在门口等着,直到保护这个点的点都被到达,限制解除,之后方可通过
通过一个点的时刻 = max(到达该点的时刻,保护该点的所有点都被到达的最后时刻)。
Code:
code1:
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 3100;
int n, m;
int Map[MAXN][MAXN];
int num[MAXN]; //记录有多少个点保护这个点
int protect[MAXN][MAXN];
int dis1[MAXN]; //保护这个点的所有点被摧毁的最后时刻
int dis2[MAXN]; //到达这个点的时刻
int vis[MAXN];
void dijkstra()
{
memset(dis1, INF, sizeof(dis1)); dis1[1] = 0;
memset(vis, 0, sizeof(vis));
int Min, u;
for(int i = 1; i <= n; i++)
{
Min = INF; u = -1;
for(int j = 1; j <= n; j++)
{
if(!vis[j] && Min > max(dis1[j], dis2[j]) && !num[j])
{
Min = max(dis1[j], dis2[j]);
u = j;
}
}
if(u == -1) break;
vis[u] = 1;
for(int j = 1; j <= n; j++)
{
if(!vis[j])
{
if(protect[u][j])
{
num[j]--;
dis2[j] = max(dis2[j], Min);
}
dis1[j] = min(dis1[j], Min + Map[u][j]);
}
}
}
}
int main()
{
cin >> n >> m;
memset(Map, INF, sizeof(Map));
for(int i = 1; i <= n; i++) Map[i][i] = 0;
int u, v, w;
while(m--)
{
cin >> u >> v >> w;
Map[u][v] = min(Map[u][v], w);
}
for(int i = 1; i <= n; i++)
{
cin >> num[i];
for(int j = 1; j <= num[i]; j++)
{
cin >> v;
protect[v][i] = 1; //v保护i
}
}
dijkstra();
cout << max(dis1[n], dis2[n]) << endl;
return 0;
}
code2:
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
const int INF = 0x3f3f3f3f;
const int MAXN = 3100;
const int MAXM = 7e4 + 9;
int n, m;
int num[MAXN];//记录都多少个点保护该点
struct Edge
{
int to, w, nxt;
}edge[MAXM];
int head[MAXN], t = 1;
void init()
{
memset(head, -1, sizeof(head));
t = 1;
}
void addEdge(int u, int v, int w)
{
edge[t].to = v;
edge[t].w = w;
edge[t].nxt = head[u];
head[u] = t++;
}
struct Edge2
{
int to, nxt;
}edge2[MAXM];
int head2[MAXN], t2 = 1;
void init2()
{
memset(head2, -1, sizeof(head2));
t2 = 1;
}
void addEdge2(int u, int v)
{
edge2[t2].to = v;
edge2[t2].nxt = head2[u];
head2[u] = t2++;
}
int dis1[MAXN];
int dis2[MAXN];
int vis[MAXN];
void dijkstra()
{
memset(dis1, INF, sizeof(dis1)); dis1[1] = 0;
memset(vis, 0, sizeof(vis));
memset(dis2, 0, sizeof(dis2));
priority_queue<pii, vector<pii>, greater<pii> >q;
q.push({dis1[1], 1});
while(!q.empty())
{
int u = q.top().second;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
int val = max(dis1[u], dis2[u]); //到达当前点u所花的时间
for(int i = head[u]; i != -1; i = edge[i].nxt)
{
int to = edge[i].to;
int w = edge[i].w;
if(!vis[to] && dis1[to] > val + w)
{
dis1[to] = val + w;
if(!num[to])
{
q.push({max(dis1[to], dis2[to]), to});
}
}
}
for(int i = head2[u]; i != -1; i = edge2[i].nxt)
{
int to = edge2[i].to;
if(num[to])
{
num[to]--;
dis2[to] = max(dis2[to], val);
}
if(!num[to]) q.push({max(dis1[to], dis2[to]), to});
}
}
}
int main()
{
cin >> n >> m;
init();
init2();
int a, b, c;
while(m--)
{
cin >> a >> b >> c;
if(a == b) continue;
addEdge(a, b, c);
}
for(int i = 1; i <= n; i++)
{
cin >> num[i];
for(int j = 1; j <= num[i]; j++)
{
cin >> a;
addEdge2(i, a);
addEdge2(a, i);
}
}
dijkstra();
cout << max(dis1[n], dis2[n]) << endl;
return 0;
}