Codeforces 1142E(圖、交互)
阿新 • • 發佈:2019-04-08
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(圖、交互)