1. 程式人生 > >Codeforces 1142E(圖、交互)

Codeforces 1142E(圖、交互)

pla class algo == 題目 turn mat using ack

題目傳送

官方題解說的很好了,剩下的就是讀大佬代碼了,前面是tarjan求SCC縮點圖。我圖論沒學過,接下來刪點是怎麽操作看得有點頭禿,直到我看到了%%%安德魯何神仙的代碼。
按照題面連通紫線以後,我們姑且先考慮從入度為0的點著手看看是否可行。由於都是入度為0的點,所以現在我們連的都是綠邊。
假如連了\[a\rightarrow b\]這條邊,而又有\[b\rightarrow c\]這條紫邊,那顯然是要斷開的,然後c如果入度為0,它也成為了一個候選。
這種做法會不會導致一開始a連向b的,然後我們把b刪了,而a其實又不是最後答案、反而b是可行的呢?

無礙,當b最後可行時,意味著b會通過別的節點和綠邊走到a,而a到b又有綠邊,也就是這是個綠環,要麽環內任意點為答案,要麽外部點為答案,走通到環內,是肯定有答案的,所以刪了b無礙。

這個做法就不需要SCC了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <functional>
using namespace std;

const int maxn = 1e5 + 5;
int n, m, used[maxn], indeg[maxn];
vector<int> adj[maxn];
queue<int> Q;

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int u, v; cin >> u >> v;
        adj[u].push_back(v);
    }

    function<void(int)> dfs = [&](int cur) {
        if (used[cur])  return;
        used[cur] = 1;
        vector<int> tmp;
        for (int son : adj[cur]) {
            if (used[son] == 1) continue;
            dfs(son);
            tmp.push_back(son);
            indeg[son]++;
        }
        used[cur] = 2;
        adj[cur] = tmp;
    };

    for (int i = 1; i <= n; i++)    dfs(i);

    for (int i = 1; i <= n; i++) {
        if (!indeg[i]) {
            Q.push(i);
        }
    }

    while (Q.size() >= 2) {
        int a = Q.front(); Q.pop();
        int b = Q.front(); Q.pop();

        cout << "? " << a << ' ' << b << '\n' << flush;
        int answer; cin >> answer;

        if (!answer)    swap(a, b);
        for (int i : adj[b]) {
            if (!--indeg[i]) {
                Q.push(i);
            }
        }
        Q.push(a);
    }

    cout << "! " << Q.front() << endl;
    return 0;
}

Codeforces 1142E(圖、交互)