1 条题解

  • 0
    @ 2026-9-23 23:23:12

    假设原图不存在孤点。

    权值为 11 的点一定是 11 号或 22 号,否则一定有至少一个与其相邻的点权值比 11 更小,但这显然不可能。

    权值为 nn 的点同理。

    我们钦定 h1=1h _ 1 = 1,h2=nh _ 2 = n。如果存在一组解中 h1=nh _ 1 = n,那么将所有 hih _ i 变为 n−hi+1n - h _ i + 1 即可调整得 h1=1h _ 1 = 1。

    假设解存在。那么可以在图上,按照 hih _ i 的大小顺序遍历每个点。设当前遍历到 u(u>2)u(u > 2) 号点,其度数为 degudeg _ u,那么在与 uu 相邻的点中,一定有恰好 degu2\frac {deg _ u} 2 个点被遍历过,它们的权值 <hu< h _ u;剩下恰好 degu2\frac {deg _ u} 2 个点没有被遍历过,它们的权值 >hu> h _ u。

    这启发我们用一个类似拓扑排序的过程来求出一组 hh。维护一个队列。初始时,将所有与 11 号相邻并且度数恰为 22 的点加入队列。对于第 ii 个出队的点 uu,令 hu=i+1h _ u = i + 1,然后将其从图中删掉。访问所有删掉 uu 之前与 uu 相邻的点 vv,设删除 uu 后 vv 的度数为 dvd _ v,若 2dv=degv2 d _ v = deg _ v,这意味着 vv 已经有恰好 degv2\frac {deg _ v} 2 个相邻的点被遍历过,这时可以将 vv 加入队列。

    如果这样的遍历不能完全进行,即除了 11 号和 22 号以外,还有点没有入过队,那么无解;如果 uu 出队时,2du≠degu2 d _ u \neq deg _ u,这不满足遍历 uu 时恰有 degu2\frac {deg _ u} 2 个相邻点被遍历过,也无解。

    若原图存在孤点,它们的权值也可以为 11 或 nn,但这并不影响。给他们随便赋几个值,剩下的部分是一样的。

    时间复杂度 O(n)O(n),实现有一些细节。

    #include <bits/stdc++.h>
    #define F(i, a, b) for(int i = (a); i <= (b); ++i)
    #define dF(i, a, b) for(int i = (a); i >= (b); --i)
    
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ull;
    typedef unsigned int uint;
    typedef pair<int, LL> pii;
    const int N = 5e5 + 5;
    
    int n, m, deg[N], h[N]; vector<int> e[N];
    
    int main() {
      // freopen("zyq.in", "r", stdin);
      // freopen("zyq.out", "w", stdout);
      ios::sync_with_stdio(0);
      cin.tie(0), cout.tie(0);
      cin >> n >> m;
      F(i, 1, m) {
        int u, v; cin >> u >> v;
        e[u].push_back(v), e[v].push_back(u);
        ++deg[u], ++deg[v];
      }
      F(i, 3, n) deg[i] >>= 1;
      h[1] = 1, h[2] = n;
      queue<int> q; int now = 1;
      F(i, 3, n) if (!deg[i]) h[i] = ++now;
      for (auto v : e[1]) --deg[v];
      F(i, 3, n) if (!h[i] && !deg[i]) q.push(i);
      while (!q.empty()) {
        int u = q.front(); q.pop(), h[u] = ++now;
        if (deg[u]) return cout << "NIE\n", 0;
        for (auto v : e[u]) if (!h[v] && !(--deg[v])) q.push(v);
      }
      if (now < n - 1) return cout << "NIE\n", 0;
      cout << "TAK\n";
      F(i, 1, n) cout << h[i] << " ";
      return 0;
    }
    
    • 1

    [POI 2020/2021 R2] 小矮人摄影 / Zdjęcia krasnali

    信息

    ID
    7536
    时间
    5000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者