Problem G. Graph 2015-2016 acmicpc neerc 拓扑排序模拟
生活随笔
收集整理的這篇文章主要介紹了
Problem G. Graph 2015-2016 acmicpc neerc 拓扑排序模拟
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一道好題
題目詳見題目連接G graph
顯然模擬拓撲排序的步驟是必不可少了。
假設我們當前有t個點,他們的入度均為0.我們不知道該選取哪一個。
我們把這t個點按從小到大排好序(放入小頂堆),假設我們目前有k條邊(k < t),我們貪心的把前k小的元素都加上一條邊,這樣的話,我們要選的就是第k+1個點,可以保證這樣選取是全局最優的。
現在問題來了,我們給前k個點加一條邊,保證了這k個點不被取到,但是,我們怎么知道這條邊的父節點是誰呢?沒錯,我們確實不知道,但是我們目前還不需要知道,所以我們打上標記,可以把他們放入一個大頂堆里面去。大頂堆里面的元素表示入度為1,但父節點尚不清楚的點。
所以每次選取的元素必然與小頂堆及大頂堆有關。
選取時,若小頂堆的大小為size,我們要盡可能挑出大的來,就要使小頂堆里的元素個數盡可能的少,所以我們盡可能用多的邊加到小頂堆里的元素上,并把這個元素移動到大頂堆里面去,直到小頂堆里面只剩一個元素。如果邊數不夠的話,就從小頂堆里面選取最小的元素。
如果邊數夠的話,小頂堆里還剩一個元素,把這個元素和大頂堆里面最大的元素作比較,如果小頂堆的元素大,那么選取小頂堆里的元素,否則給小頂堆的元素加邊,扔到大頂堆里面去,并且從大頂堆里面選取出一個最大的來。
代碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5+7; vector<int> G[maxn]; int n,m,k; int ind[maxn]; set<int> sma,big; typedef set<int>::iterator itp; int cnt; pair<int,int> ans[maxn*10]; int main(){freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); scanf("%d%d%d",&n,&m,&k);for(int i = 0;i < m;++i) {int u,v;scanf("%d%d",&u,&v);G[u].push_back(v);ind[v]++;}for(int i = 1;i <= n;++i) if(!ind[i]) sma.insert(i);int last = 0;while(sma.size() || big.size()){int rt;itp it;int edges,pre;if(sma.size() == 0){goto mark;}it = sma.begin();edges = min(k,(int)sma.size()-1);pre = 0;for(int i = 0;i < edges;++i){pre = *it;itp nit = it;nit++;sma.erase(it);big.insert(pre);it = nit;}k -= edges;if(k && big.size() && *big.rbegin() > *sma.begin()){k -= 1;big.insert(*sma.begin());sma.clear();mark:rt = *big.rbegin();big.erase(big.find(*big.rbegin()));ans[cnt++] = make_pair(last,rt);}else{rt = *sma.begin();sma.erase(sma.begin());}for(int i = 0;i < G[rt].size();++i){--ind[G[rt][i]];if(ind[G[rt][i]] == 0) sma.insert(G[rt][i]);}printf("%d ",rt);last = rt;}printf("\n%d\n",cnt);for(int i = 0;i < cnt;++i){printf("%d %d\n",ans[i].first,ans[i].second);}return 0; } /* 7 4 1 2 1 4 3 4 6 6 7*/總結
以上是生活随笔為你收集整理的Problem G. Graph 2015-2016 acmicpc neerc 拓扑排序模拟的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: poj3648 Wedding 2-sa
- 下一篇: 得意洋洋的近义词 得意洋洋的近义词介绍