【opentrains 10530K】We apologize for any inconvenience (Floyd)

不会放题目链接qwq,opentrains的UI太丑了

题目大意

n n n 个站台和 k k k 路地铁,依次停开 s s s 列地铁,每停开一列,输出所有车站对之间的最小转车数(不可达的不考虑)
n , k ≤ 750 n,k\le 750 n,k750

思路

建立一个两侧点数分别为 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值