D. Toss a Coin to Your Graph_二分答案+拓撲
阿新 • • 發佈:2022-05-17
D. Toss a Coin to Your Graph_二分+拓撲
題目大意
在圖中找一個長度大於等於k的鏈使得其中的最大值最小。
思路和程式碼
很好的題目
首先,最大值的最小很容易就可以想到二分
每次在值小於等於mid的圖裡面做拓撲序bfs,維護ds陣列,dsi表示從拓撲序起點到點i的最多點數。
ll n , m , k ; int a[N] ; bool ck(ll x , vct<vct<int> > &eg){ //用所有數值小於等於x的點建圖 //找一條長度大於k的鏈 vct<ll> ds(n + 1 , 0) ; vct<int> din(n + 1 , 0) ; vct<bool> ing(n + 1 , 0) ; int num = 0 ; rep(u , 1 , n){ if(a[u] > x) continue ; num ++ ; ing[u] = 1 ; for(int v : eg[u]){ if(a[v] > x) continue ; din[v] ++ ; } } queue<int> q ; rep(i , 1 , n) if(ing[i] && !din[i]){ q.push(i) ; ds[i] = 1 ; } while(q.size()){ int now = q.front() ; q.pop() ; num -- ; for(int nxt : eg[now]){ if(!ing[nxt]) continue ; ds[nxt] = max(ds[nxt] , ds[now] + 1LL) ; if(! -- din[nxt]) q.push(nxt) ; } } if(num > 0) return 1 ; rep(i , 1 , n) if(ing[i] && ds[i] >= k) return 1 ; return 0 ; } void solve(){ cin >> n >> m >> k ; get1(a , 1 , n) ; vct<vct<int> > eg(n + 1) ; rep(i , 1 , m){ int u , v ; cin >> u >> v ; eg[u].pb(v) ; } ll l = 1 , r = mod ; while(l < r){ // cout << l << " " << r << "," ; int mid = l + r >> 1 ; if(ck(mid , eg)) r = mid ; else l = mid + 1 ; } cout << (l < mod ? l : -1) << "\n" ; }//code_by_tyrii