Solution -「CF 1391E」Pairs of Pairs
阿新 • • 發佈:2020-09-14
\(\mathcal{Description}\)
Link.
給定一個 \(n\) 個點 \(m\) 條邊的無向圖,在其上找到一條包括不少於 \(\lceil\frac{n}2\rceil\) 個結點的簡單路徑;或者將至少 \(\lceil\frac{n}2\rceil\) 個結點劃分為若干二元組,使得任意兩個不同二元組內四個結點的匯出子圖含有至多兩條邊。多組資料。
\(n,\sum n\le5\times10^5\),\(m,\sum m\le10^6\)。
\(\mathcal{Solution}\)
去分開剛兩個 NP 問題,請。
這種給兩個問題讓你解其中一個的,顯然以嘗試求解一個失敗為條件
由於 DFS 樹沒有橫叉邊,所以在樹上某一結點的左子樹選一個,右子樹選一個來組成一對,這兩對間的匯出子圖顯然不超過兩條邊。所以用 std::vector
記錄子樹內匹配剩下的結點,在父親處與兄弟子樹剩下的結點配對即可。可以證明在樹深 \(<\lceil\frac{n}2\rceil\) 的情況下一定有解。
\(\mathcal{Code}\)
/* Clearink */ #include <cstdio> #include <vector> #include <cstdlib> #include <assert.h> inline int rint () { int x = 0, f = 1; char s = getchar (); for ( ; s < '0' || '9' < s; s = getchar () ) f = s == '-' ? -f : f; for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' ); return x * f; } template<typename Tp> inline void wint ( Tp x ) { if ( x < 0 ) putchar ( '-' ), x = ~ x + 1; if ( 9 < x ) wint ( x / 10 ); putchar ( x % 10 ^ '0' ); } const int MAXN = 5e5, MAXM = 1e6; int n, m, ecnt, head[MAXN + 5], p[MAXN + 5]; bool vis[MAXN + 5], solved; std::vector<int> path, rest[MAXN + 5]; std::vector<std::pair<int, int> > pairs; struct Edge { int to, nxt; } graph[MAXM * 2 + 5]; inline void link ( const int s, const int t ) { graph[++ ecnt] = { t, head[s] }; head[s] = ecnt; } inline void clear () { ecnt = solved = 0, path.clear (), pairs.clear (); for ( int i = 1; i <= n; ++ i ) head[i] = vis[i] = 0, rest[i].clear (); } inline void printPath () { solved = true; printf ( "PATH\n%d", ( int ) path.size () ); for ( int i = 0; i ^ path.size (); ++ i ) { printf ( "%c%d", i ? ' ' : '\n', path[i] ); } putchar ( '\n' ); } inline void printPairs () { solved = true; printf ( "PAIRING\n%d\n", ( int ) pairs.size () ); for ( auto p: pairs ) printf ( "%d %d\n", p.first, p.second ); } inline void solve ( const int u ) { if ( solved ) return ; vis[u] = true, path.push_back ( u ), p[u] = u; if ( ( int ) path.size () << 1 >= n ) printPath (); for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( !vis[v = graph[i].to] ) { solve ( v ), path.pop_back (); if ( solved ) return ; while ( !rest[p[u]].empty () && !rest[p[v]].empty () ) { pairs.push_back ( { rest[p[u]].back (), rest[p[v]].back () } ); if ( ( int ) pairs.size () << 2 >= n ) return printPairs (); rest[p[u]].pop_back (), rest[p[v]].pop_back (); } p[u] = rest[p[u]].empty () ? p[v] : p[u]; } } rest[p[u]].push_back ( u ); } int main () { for ( int T = rint (); T --; ) { n = rint (), m = rint (), clear (); for ( int i = 1, u, v; i <= m; ++ i ) { u = rint (), v = rint (); link ( u, v ), link ( v, u ); } solve ( 1 ); assert ( solved ); } return 0; }
\(\mathcal{Details}\)
std::vector
的操作能少壓入就少壓入啊……不知道怎麼記憶體就掛掉了。