Loading

【题解】FARIO2019-Nav

交互题,给定一张 \(n\) 个点无向图,进行 \(k\) 局游戏,每局先初始化一个点 \(x\),选手每次询问一个点 \(u\),返回 \(u\)\(x\) 某条最短路上的某条边。需要在 \(9\) 次操作内求出点 \(x\)\(n\le 300,k\le 750\)

对于一条链的情况,可以直接二分。一棵树的情况可以直接点分治。

那么对于图的情况,我们求出每个点出发的最短路图,对这个 DAG 求出最劣情况下能排除多少个点,然后取最优的 DAG 分治。

结论,每次取最优的 DAG,决策集合至少减半。还不太会证明。

先 Floyd 求任意两点最短路,每次询问及时更新决策集合与 DAG。复杂度是 \(\mathcal{O}(n^3 + k(n^2 + m\log n))\)

int n, d[N][N];
int nav(int);
vector<int>e[N];
vector<Pr>o;
void init(int subtask, int n_, int m, std::vector<int> A, std::vector<int> B) {
	n = n_; memset(d, 0x3f, sizeof(d));
	o.resize(m);
	rep(i, 0, m - 1){
		A[i] ++, B[i] ++, o[i] = {A[i], B[i]};
		d[A[i]][B[i]] = d[B[i]][A[i]] = 1;
		e[A[i]].pb(B[i]), e[B[i]].pb(A[i]);
	}
	rp(i, n)d[i][i] = 0;
	rp(k, n)rp(i, n)rp(j, n)cmn(d[i][j], d[i][k] + d[k][j]);
}
vector<int>c;
int calc(){
	if(si(c) == 1)return c[0] - 1;
	int mn = inf, u = ~0;
	go(x, c){
		int mx = 0;
		go(y, e[x]){
			int sum = 0;
			go(z, c)sum += d[y][z] + 1 == d[x][z];
			cmx(mx, sum);
		}
		if(mx < mn)mn = mx, u = x;
	}
	assert(~u);
	int p = nav(u - 1);
	if(-1 == p)return u - 1;
	int x = o[p].fi, y = o[p].se;
	if(d[u][x] > d[u][y])swap(x, y);
	vector<int>res;
	go(x, c)if(d[u][y] + d[y][x] == d[u][x])res.pb(x);
	c = res; return calc();
}
int findPrime() {
	//rp(i, n){rp(j, n)printf("%d ", d[i][j]); el;}
	c.clear();
	rp(i, n)c.pb(i);
	return calc();
}
posted @ 2022-08-08 12:02  7KByte  阅读(82)  评论(0编辑  收藏  举报