假(?)做法求 hack 数据
查看原帖
假(?)做法求 hack 数据
353967
baoyangawa楼主2024/9/2 19:18

从 S,U,VS, U, V 分别进行 dijkstra。

我们记 duxdu_x 为 UU 到 xx 的最短路径长度,dvxdv_x 同理。取一条 SS 到 TT 的最短路,记该路径为 pp,则答案为 min⁡x∈pdux+min⁡x∈pdvx\min\limits_{x\in p}du_x +\min\limits_{x\in p}dv_x。

把 SS 到 TT 所有可能的最短路上的边保留,方向钦定为 dijkstra 转移的反方向。于是形成了一张以 TT 为起点的 DAG。

我们在 DAG 上进行 dp。对每个点 xx 记录 puxpu_x 和 pvxpv_x,表示 xx 到 TT 选取某条路径,其中 dudu 和 dvdv 的最小值,满足 pux+pvxpu_x + pv_x 尽可能优。

考虑一个转移。最开始令 pux=pvx=∞pu_x = pv_x = \infin,若记录能到达 xx 点的集合为 AA,则对于每个点 y∈Ay\in A,若 min⁡(puy,dux)+min⁡(pvy+dux)≤min⁡(pux,dux)+min⁡(pvx+dvx)\min(pu_y,du_x) +\min(pv_y+du_x)\le\min(pu_x,du_x)+\min(pv_x+dv_x),则使 pux←puypu_x \leftarrow pu_y,pvx←pvypv_x\leftarrow pv_y。

所有的 y∈Ay\in A 都转移完了之后(也就是拓扑排序中 xx 点入度为 00 时),我们令 pux←min⁡(pux,dux)pu_x \leftarrow \min(pu_x,du_x),pvx←min⁡(pvx+dvx)pv_x\leftarrow \min(pv_x+dv_x),然后再向外转移。

这部分的代码实现:

ll rd[N], pu[N], pv[N]; // rd 为入度
vector <ll> frm[N]; // frm[x] 为 x 的出边对应的点集
void top_sort() {
	for (int i = 1; i <= n; i++) pu[i] = INF, pv[i] = INF;
	pu[t] = du[t], pv[t] = dv[t];
	queue <ll> q; q.push(t); 
	while (!q.empty()) {
		ll y = q.front(); q.pop();
		for (auto x : frm[y]) {
			if (min(pu[x], du[x]) + min(pv[x], dv[x]) >= min(pu[y], du[x]) + min(pv[y], dv[x])) pu[x] = pu[y], pv[x] = pv[y];
			rd[x]--;
			if (rd[x] == 0) {
				pu[x] = min(pu[x], du[x]);
				pv[x] = min(pv[x], dv[x]);
				q.push(x);
			}
		}
	} return;
}

这东西假的离谱(?)。想象中有个样例:

其中黑色字体为 (dux,dvx)(du_x, dv_x),红色字体为 (pux,pvx)\color{red}(pu_x, pv_x)。我们发现对于 44 号点,选择向 55 走时答案为 99+1=10099+1=100,向 66 号点走时答案为 2+2=42+2=4,于是选择了 66 号点。

进而,实际选择了标红的这条最短路。但显然正确答案应该是 S−2−4−5−TS-2-4-5-T 这条最短路,能得到 1+1=21+1=2 的最小答案。

请大佬构造一组能够卡掉这个做法的数据,或者证明这样的数据构造不出来,万分感谢!!!

提交记录

2024/9/2 19:18
加载中...