UOJ461 新年的Dog劃分【圖論,互動】
阿新 • • 發佈:2021-06-24
這是一道互動題
互動庫有 \(n\) 個點 \(m\) 條邊的簡單無向連通圖,至多 \(2000\) 次詢問一個邊集 \(E'\),互動庫告訴你把 \(E'\) 中的邊去掉之後圖是否連通。求這張圖是不是二分圖,如果是則求一側。
\(2\le n\le 200\)。
\(n^2\) 次詢問就可以把整個圖求出來,拿到了丟人的 \(37\) 分。
又忘了,連通無向圖->生成樹。
可以 bfs 把生成樹求出來,每次找出當前點連出的所有邊,可以直接大力二分,最後求出染色方案並 check 一下。
check 染色方案就列舉一條樹邊斷掉,並把除樹邊外的異色邊斷掉,如果連通說明不合法。
總詢問次數大約 \((\lceil\log_2n\rceil+2)n\)
#include<bits/stdc++.h> #include"graph.h" #define PB emplace_back using namespace std; typedef vector<int> VI; typedef pair<int, int> pii; const int N = 203; int Q[N], fr, re; VI q, ans, G[N]; vector<pii> now, tmp, edg; bool col[N], vis[N], fal[N][N], tre[N][N]; int work(int u){ if(q.empty()) return -1; int l = 0, r = q.size()-1, md; auto qry = [&](int r){ tmp = now; for(int i = 0;i <= r;++ i) tmp.PB(u, q[i]); return query(tmp); }; if(qry(r)){ for(int i = 0;i <= r;++ i){ fal[u][q[i]] = fal[q[i]][u] = true; now.PB(u, q[i]); } return -1; } while(l < r) qry(md = l+r>>1) ? l = md+1 : r = md; for(int i = 0;i < l;++ i){ fal[u][q[i]] = fal[q[i]][u] = true; now.PB(u, q[i]); } return q[l]; } void dfs(int x, int f){ for(int v : G[x]) if(v != f){ col[v] = !col[x]; dfs(v, x); } } VI check_bipartite(int n){ vis[0] = true; Q[re++] = 0; while(fr < re){ int u = Q[fr]; q.resize(0); for(int i = 0;i < n;++ i) if(!vis[i] && !fal[u][i]) q.PB(i); int v = work(u); if(v == -1){++fr; continue;} Q[re++] = v; tre[u][v] = tre[v][u] = vis[v] = true; G[u].PB(v); G[v].PB(u); edg.PB(u, v); } dfs(0, 0); tmp.resize(0); for(int i = 0;i < n;++ i) if(!col[i]) for(int j = 0;j < n;++ j) if(col[j] && !tre[i][j]) tmp.PB(i, j); tmp.PB(); for(int x = 0;x < n-1;++ x){ tmp.back() = edg[x]; if(query(tmp)) return VI(); } for(int i = 0;i < n;++ i) if(!col[i]) ans.PB(i); return ans; }