题解:P6543 [CEOI2014] 007
洛谷 P6543 [CEOI2014] 007 & LOJ #3289. 「CEOI2014」007。
upd on 2024/10/15 13:12:40:修改一处笔误。 upd on 2024/10/15 14:39:45:修改亿处笔误。
题意
在无向无权图上有警、匪和相邻的两处机密,每回合匪先走,警后走,可以不走,匪目标为走到某处机密并花一回合获得,警目标是在匪获得机密前某一回合走到匪当时所在的点,求警最多可以摆烂几回合(摆烂时无法抓匪)。
数据范围:点数
题解
先后走无关紧要,看作同时走,即警最晚需要在匪到机密时走到匪的位置。
首先容易发现警可以在机密处「守株待小粉兔」,因此警一定走最短路,所以匪也一定走最短路。那么容易判掉
设
那么这是不是最终答案呢?稍加思考便可以举出反例:有可能匪「虚晃」了一下警,把警骗到歧路中后抄近道,这时答案需要减一。例如下面这张图:
P.S. 略微不对称,强迫症体谅一下 :)
P.P.S 如果
在这个例子里,
- 第一回合:匪走到
8 ;警摆烂。 - 第二回合:匪走到
6 ;警走到2 。 - 第三回合:匪走到
5 ;警走到4 。 - 第四回合:匪获胜。
这样警就必须提前一回合出发,答案需要减一。
那么何时答案需要减一呢?仔细思考,可以发现问题一定出在 从
当然这样做有前提条件,就是
剩下的代码就很好写了,判掉无解,找到上限,找到最长重合位置(
constexpr int N = 200005;
constexpr ll mod = 998244353;
int n, m, s, t, x, y, k;
vector<int> G[N];
int ds[4][N];
int qu[N], lh, rt;
#define d ds[t]
void bfs(int s, int t) {
qu[lh = rt = 1] = s, d[s] = 0; while (lh <= rt) {
int u = qu[lh++];
for (auto v : G[u]) if (d[v] < 0) d[v] = d[u] + 1, qu[++rt] = v;
}
}
void solve() {
scanf("%d%d%d%d%d%d", &n, &m, &s, &t, &x, &y); rep(i, 1, m) {
int u, v; scanf("%d%d", &u, &v);
G[u].emplace_back(v), G[v].emplace_back(u);
} mem(ds, -1), bfs(s, 0), bfs(t, 1);
if (int d1 = ds[1][x] - ds[0][x], d2 = ds[1][y] - ds[0][y]; (k = min(d1, d2)) < 0) { puts("-1"); return; }
else if (d1 != d2) printf("%d\n", k);
else {
int p = 0, q = 0; bfs(x, 2), bfs(y, 3);
rep(i, 1, n) if (ds[2][i] == ds[3][i]) {
if (ds[0][i] + ds[2][i] == ds[0][x]) chkmx(p, ds[0][i]);
if (ds[1][i] + ds[3][i] == ds[1][y]) chkmx(q, ds[1][i]);
}
printf("%d\n", k - (p + k < q));
}
}