跳转至

L - Median

基本信息

题目出处2019 山东省大学生程序设计竞赛
队伍通过率61/307 (19.9%)

题解

如果 \(a_u\) 严格比 \(a_v\) 大,则从 \(u\)\(v\) 连一条有向边,得到一张有向图。有向图中,如果点 \(u\) 能走到点 \(v\),说明 \(u\) 严格比 \(v\) 大;如果 \(u\) 走不到 \(v\)\(v\) 也走不到 \(u\),说明两者之间没有大小限制。

如果有向图中有环说明无解(因为不可能自己严格比自己大),否则这张图是一张有向无环图。对于点 \(u\),如果它的前继(能走到它的点)数量大于 \(\lfloor\frac{n}{2}\rfloor\),说明已知严格比它大的数已经超过了 \(\lfloor\frac{n}{2}\rfloor\) 个,\(u\) 不可能是中位数;同理,如果 \(u\) 的后继(它能走到的点)数量大于 \(\lfloor\frac{n}{2}\rfloor\),说明已知严格比它小的数已经超过了 \(\lfloor\frac{n}{2}\rfloor\) 个,\(u\) 也不可能是中位数。剩下的情况,\(u\) 就可以作为中位数。

因此利用 bfs 或 dfs 统计每个点的前继和后继数量即可。复杂度 \(\mathcal{O}(nm)\)

参考代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <bits/stdc++.h>
#define MAXN 100
using namespace std;

int n, m;

vector<int> e[MAXN + 10];
int pre[MAXN + 10], suc[MAXN + 10];
int vis[MAXN + 10];

// 找出 S 的所有后继,如果发现包含 S 的环返回 false,否则返回 true
bool bfs(int S) {
    queue<int> q;
    q.push(S); vis[S] = S;
    while (!q.empty()) {
        int sn = q.front(); q.pop();
        for (int fn : e[sn]) {
            if (fn == S) return false;
            if (vis[fn] == S) continue;
            q.push(fn); vis[fn] = S;
            // fn 是 S 的后继,S 也是 fn 的前继
            pre[fn]++; suc[S]++;
        }
    }
    return true;
}

void solve() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) e[i].clear();
    for (int i = 1; i <= m; i++) {
        int x, y; scanf("%d%d", &x, &y);
        e[x].push_back(y);
    }

    memset(pre, 0, sizeof(int) * (n + 3));
    memset(suc, 0, sizeof(int) * (n + 3));
    memset(vis, 0, sizeof(int) * (n + 3));
    for (int i = 1; i <= n; i++) if (!bfs(i)) {
        // 有环,无解
        for (int j = 1; j <= n; j++) printf("0");
        printf("\n");
        return;
    }

    for (int i = 1; i <= n; i++)
        // 前后继都不超过 floor(n / 2),可以作为中位数
        if (pre[i] <= n / 2 && suc[i] <= n / 2) printf("1");
        else printf("0");
    printf("\n");
}

int main() {
    int tcase; scanf("%d", &tcase);
    while (tcase--) solve();
    return 0;
}