不会放题目链接qwq,opentrains的UI太丑了
题目大意
有
n
n
n 个站台和
k
k
k 路地铁,依次停开
s
s
s 列地铁,每停开一列,输出所有车站对之间的最小转车数(不可达的不考虑)
n
,
k
≤
750
n,k\le 750
n,k≤750
思路
建立一个两侧点数分别为
n
,
k
n, k
n,k 的二分图,跑Floyd。
先对站台以及未停开的地铁进行松弛,然后按时间倒序对停开的地铁进行松弛。每松弛一次,记录站台之间的最大转车数。
代码
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define per(i, r, l) for (int i = r; i >= l; --i)
using namespace std;
const int inf = 0x3fffffff;
const int N = 755;
int T;
int n, k;
int s;
int can[N];
bool ban[N];
int dis[N + N][N + N];
int ans[N];
void output() {
rep(i, 1, n + k) {
rep(j, 1, n + k) { printf("%12d ", dis[i][j]); }
printf("\n");
}
printf("\n");
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &k);
rep(i, 1, n + k) {
rep(j, 1, n + k) { dis[i][j] = (i == j) ? 0 : inf; }
}
// train & stop
rep(i, 1, k) { // train n+i
int cnt;
scanf("%d", &cnt);
rep(j, 1, cnt) {
int x;
scanf("%d", &x); // stop x
dis[n + i][x] = dis[x][n + i] = 1;
}
}
// train & train
rep(i, 1, k) { // train n+i
rep(j, i + 1, k) { // train n+j
rep(kk, 1, n) { // stop kk
if (dis[n + i][kk] == 1 && dis[n + j][kk] == 1) {
dis[n + i][n + j] = dis[n + j][n + i] = 2;
break;
}
}
}
}
// output();
rep(i, 1, k) ban[i] = false;
scanf("%d", &s);
rep(i, 1, s) {
scanf("%d", &can[i]);
ban[can[i]] = true;
}
rep(x, 1, k) { // train n+x
if (ban[x]) continue;
rep(i, 1, n + k) {
rep(j, 1, n + k) {
if (dis[i][j] > dis[i][n + x] + dis[n + x][j]) {
dis[i][j] = dis[i][n + x] + dis[n + x][j];
}
}
}
}
ans[s + 1] = 0;
rep(i, 1, n) {
rep(j, 1, n) {
if (dis[i][j] != inf) {
ans[s + 1] = max(ans[s + 1], dis[i][j]);
}
}
}
// output();
per(t, s, 1) {
int x = can[t]; // add train n+x
ans[t] = 0;
rep(i, 1, n + k) {
rep(j, 1, n + k) {
if (dis[i][j] > dis[i][n + x] + dis[n + x][j]) {
dis[i][j] = dis[i][n + x] + dis[n + x][j];
}
if (i <= n && j <= n && dis[i][j] != inf) {
ans[t] = max(ans[t], dis[i][j]);
}
}
}
// output();
}
rep(i, 1, s + 1) { printf("%d\n", (ans[i] - 2) / 2); }
}
return 0;
}