[SDOI2010] 大陆争霸
[SDOI2010] 大陆争霸
第一眼看上去好像是最短路加了个强制拓扑。
也就是说当结界还没被破坏的时候,已经到达的机器人只能干等着。
在 dijkstra 中,机器人所在的点可以更新最短路。但拓扑图上该点的入度不为 \(0\),即结界产生器没有被全部破坏时,不能入队。
当炸掉一个结界产生器的时候,可以将其在拓扑图上连接的所有点的入度减一。
而当拓扑图上的一个点入度为 \(0\),即结界产生器全部被破坏的时候,便可以入队。
不用考虑当前是否有机器人在该点等待。即使没有,由于题目保证有解,所以若该点在 \(1\to n\) 的最短路上一定可达。之后也会有更优决策来替代它。
#include <bits/stdc++.h>
typedef long long ll;
const int maxn = 3e3 + 20, maxm = 7e4 + 20;
ll dis[maxn];
int mk[maxn];
struct Graph {
struct edge {
int u, v, w, next;
} e[maxm];
int head[maxn], idx;
int inDeg[maxn];
void add(int x, int y, int z) {
inDeg[y]++;
idx++; e[idx].u = x, e[idx].v = y, e[idx].w = z;
e[idx].next = head[x], head[x] = idx;
}
Graph() {
memset(head, 0, sizeof head);
idx = 0;
}
};
struct point {
int u; ll dis;
point(int a, ll b) {u = a, dis = b;}
friend bool operator < (point a, point b) {
return a.dis > b.dis;
}
};
void dijkstra(int st, int end, Graph &G, Graph &tG) {
memset(dis, 0x3f, sizeof dis);
memset(mk, 0, sizeof mk);
std::priority_queue <point> q;
q.push(point(st, 0)); dis[st] = 0;
while(!q.empty()) {
int u = q.top().u; q.pop();
if(u == end) return;
if(mk[u]) continue;
mk[u] = 1;
for(int i = tG.head[u]; i; i = tG.e[i].next) {
int v = tG.e[i].v; tG.inDeg[v]--;
dis[v] = std::max(dis[u], dis[v]);
if(tG.inDeg[v] == 0) q.push(point(v, dis[v]));
}
for(int i = G.head[u]; i; i = G.e[i].next) {
int v = G.e[i].v, w = G.e[i].w;
if(dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if(tG.inDeg[v] == 0) q.push(point(v, dis[v]));
}
}
}
}
int n, m;
Graph G, topoG;
void solve() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
G.add(u, v, w);
}
for(int i = 1; i <= n; i++) {
int num; scanf("%d", &num);
for(int j = 1; j <= num; j++) {
int x; scanf("%d", &x);
topoG.add(x, i, 0);
}
}
dijkstra(1, n, G, topoG);
printf("%lld", dis[n]);
}
int mian(){
solve();
return 0;
}