CodeForces 1361E James and the Chase(dfs + 结论)
problem
洛谷鏈接
solution
看到這個 20%20\%20% 的特殊性質,腦海里第一個就想到了隨機化算法。已經PTSD了著實上頭
如果本題只是隨便求一個 interesting\text{interesting}interesting 的點,那就非常簡單了。
隨機化一個點,檢查這個點是否滿足 interesting\text{interesting}interesting 的限制即可。
如果判斷一個點是否是 interesting\text{interesting}interesting 的點?以該點為根建立 dfs-tree。如果只有樹邊和返祖邊,沒有一條橫叉邊,那么這個點就是“有趣點”。
一次判斷的復雜度是 O(n)O(n)O(n) 的。
執行 min?(100,n)\min(100,n)min(100,n) 次,正確率就高達 1?(45)1001-(\frac{4}{5})^{100}1?(54?)100。
雖然很簡單,但是本題的正解就是建立在這種隨機的基礎上的。
我們不能求出所有點,但是可以快速通過隨機求出一個 interesting\text{interesting}interesting 點,記為 ididid。
以 ididid 為根,建立 dfs-tree ,那么這棵樹是沒有橫叉邊的。
考慮能否在這棵樹上求出所有的 interesting\text{interesting}interesting 點。
顯然是可以的,需要用到幾個小性質。
定理1 樹上一個非根節點 uuu 的子樹內至少會有一條連向子樹外的邊(跨過 uuu),即返祖邊。
這是顯然的,因為題目保證點兩兩之間是可以互達的。
定理2 如果樹上一個非根節點 uuu 的子樹內有不止一條連向子樹外的邊,則該點不是 interesting\text{interesting}interesting 點。
- 如果兩條返祖邊都指向同一個祖先,也就意味著 uuu 有兩條到達這個祖先的路徑。
- 如果兩條返祖邊指向不同的祖先,但這兩組先之間也存在祖先后輩關系,相當于到某個輩分較小的祖先也有兩條路徑。
定理3 如果樹上一個非根節點 uuu 的子樹內只有一條連向子樹外的邊,uuu 是“有趣點” 當且僅當這條返祖邊連向的祖先也是“有趣點”。
這也是顯然的。uuu 到這個祖先是一條簡單路徑,祖先不是“有趣點”就意味著祖先到某個點有不止一條路徑。傳遞過來等價于 uuu 到某個點也有不止一條路徑。
請時刻注意,根 ididid 一定是“有趣點”,樹一定沒有橫叉邊。
所以我們可以通過 dfs 來完成篩選。
code
#include <bits/stdc++.h> using namespace std; #define maxn 100005 bool flag; int T, n, m; vector < int > ans, G[maxn]; int dep[maxn], low[maxn], cnt[maxn], vis[maxn]; bool bad[maxn];void dfs_good( int u ) {if( ! flag ) return;vis[u] = 1;for( int v : G[u] )if( ! vis[v] ) dfs_good( v );else if( vis[v] == 2 ) { flag = 0; return; }vis[u] = 2; }int dfs( int u ) {vis[u] = 1, low[u] = u;for( int v : G[u] )if( ! vis[v] ) {dep[v] = dep[u] + 1;cnt[u] += dfs( v );if( dep[low[v]] < dep[low[u]] ) low[u] = low[v];} //為什么選深度最小的點呢?因為這個點的輩分最大 能跨過這個點的返祖邊對應的點越少else {cnt[u] ++, cnt[v] --;//因為之前是直接把后代的返祖邊加上來的,但是這些返祖邊對于這個祖先而言還是后代之間的連邊 并未跨過這個祖先if( dep[v] < dep[low[u]] ) low[u] = v;}if( cnt[u] > 1 ) bad[u] = 1;return cnt[u]; }void dfs_bad( int u ) {vis[u] = 1;if( bad[low[u]] ) bad[u] = 1;for( int v : G[u] ) if( ! vis[v] ) dfs_bad( v ); }int main() {mt19937 wwl(time(0));scanf( "%d", &T );while( T -- ) {ans.clear();for( int i = 1;i <= n;i ++ ) {G[i].clear();low[i] = bad[i] = dep[i] = cnt[i] = vis[i] = 0;}scanf( "%d %d", &n, &m );for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );}uniform_int_distribution < int > range( 1, n );int id = -1;for( int t = 1;t <= 100;t ++ ) {flag = 1;for( int i = 1;i <= n;i ++ ) vis[i] = 0;id = range( wwl );dfs_good( id );if( flag ) break;}if( ! flag ) { puts( "-1" ); continue; }for( int i = 1;i <= n;i ++ ) vis[i] = 0;dfs( id );for( int i = 1;i <= n;i ++ ) vis[i] = 0;dfs_bad( id );for( int i = 1;i <= n;i ++ )if( ! bad[i] ) ans.push_back( i );sort( ans.begin(), ans.end() );if( ans.size() * 5 < n ) printf( "-1" );else for( int i : ans ) printf( "%d ", i );printf( "\n" );}return 0; }總結
以上是生活随笔為你收集整理的CodeForces 1361E James and the Chase(dfs + 结论)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 杨万里
- 下一篇: PowerDesigner16.5 安装