hdu 5195 DZY Loves Topological Sorting BestCoder Round #35 1002 [ 拓撲排序 + 優先隊列 || 線段樹 ]


傳送門

DZY Loves Topological Sorting

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 221    Accepted Submission(s): 52


Problem Description
A topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge (uv) from vertex u to vertex v , u comes before v in the ordering.
Now, DZY has a directed acyclic graph(DAG). You should find the lexicographically largest topological ordering after erasing at most k edges from the graph.
 

 

Input
The input consists several test cases. ( TestCase5 )
The first line, three integers n,m,k(1n,m105,0km) .
Each of the next m lines has two integers: u,v(uv,1u,vn) , representing a direct edge(uv) .
 

 

Output
For each test case, output the lexicographically largest topological ordering.
 

 

Sample Input
5 5 2 1 2 4 5 2 4 3 4 2 3 3 2 0 1 2 1 3
 

 

Sample Output
5 3 1 2 4 1 3 2
Hint
Case 1. Erase the edge (2->3),(4->5). And the lexicographically largest topological ordering is (5,3,1,2,4).
 

 

Source
 

 

Recommend
hujie   |   We have carefully selected several similar problems for you:   5197  5196  5193  5192  5189 
 
 
http://bestcoder.hdu.edu.cn/
 
Problem B - DZY Loves Topological Sorting
因為我們要求最后的拓撲序列字典序最大,所以一定要貪心地將標號越大的點越早入隊。我們定義點i的入度為di。假設當前還能刪去k條邊,那么我們一定會把當前還沒入隊的dik的最大的i找出來,把它的di條入邊都刪掉,然后加入拓撲序列。可以證明,這一定是最優的。 具體實現可以用線段樹維護每個位置的di,在線段樹上二分可以找到當前還沒入隊的dik的最大的i。於是時間復雜度就是O((n+m)logn).


不過,這里面說的還有一點不太清楚,
轉一下另一個題解:
http://blog.csdn.net/glqac/article/details/44710897

看題意以為是個拓撲排序。事實上,就是個線段樹。因為最多可以刪k條邊, 所以就是在線段樹里找入度小於等於k的最大值,那么保存個區間最小就ok了。如果右子樹的區間最小小於等於k那么就往右邊走,因為是要找字典序最大的。當k是0,也是這樣找,就跟topological sort是一樣的。然后刪除一個點就在線段樹那個點置最大值,再刪除他的邊。因為總共也就m條邊不超過10^5。

總復雜度o(n+m)logn。

 

我的解法:

用優先隊列,當前節點的入度小於k便入隊列,出隊列時以節點編號為優先權,如果小於等於k,則輸出,反之,跳過。不過寫的時候遇到幾個問題:

1.節點重復入隊列沒事,但是,不能讓已經在隊列中的再入隊列。故要用vis,vis=0暫時不在隊列中,vis=-1,在隊列中,vis=1,已經輸出。

2.判斷隊首元素的入度是否 小於k時,要用現在的入度,而不是入隊列時的入度,因為,可能在處理其它點的時候,該點的入度已經發生了變化。

 

總的來說,還是線段樹的方法思路清晰~~

 

13278084 2015-03-29 08:49:19 Accepted 5195 561MS 6988K 2158 B C++ czy
13278083 2015-03-29 08:49:04 Time Limit Exceeded 5195 2000MS 8308K 2158 B G++ czy

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <stack>
  4 #include <vector>
  5 #include <map>
  6 #include <algorithm>
  7 #include <queue>
  8 
  9 #define ll long long
 10 int const N = 100005;
 11 int const M = 205;
 12 int const inf = 1000000000;
 13 ll const mod = 1000000007;
 14 
 15 using namespace std;
 16 
 17 int n,m;
 18 int k;
 19 int vis[N];
 20 vector<int> bian[N];
 21 int r[N];
 22 
 23 struct node
 24 {
 25     friend bool operator < (node n1,node n2)
 26     {
 27         return n1.index  < n2.index;
 28     }
 29     int index;
 30     int d;
 31 };
 32 
 33 void ini()
 34 {
 35     int u,v;
 36     memset(r,0,sizeof(r));
 37     memset(vis,0,sizeof(vis));
 38     int i;
 39     for(i=0;i<=n;i++){
 40         bian[i].clear();
 41     }
 42     for(i=1;i<=m;i++){
 43         scanf("%d%d",&u,&v);
 44         r[ v ]++;
 45         bian[ u ].push_back( v );
 46     }
 47 
 48 }
 49 
 50 void solve()
 51 {
 52     node te,nt;
 53     int i;
 54     priority_queue<node> que;
 55     for(i=n;i>=1;i--){
 56         if(r[ i ]<=k){
 57             te.index=i;
 58             te.d=r[i];
 59             que.push(te);
 60             vis[i]=-1;
 61         }
 62     }
 63 
 64     int ff=0;
 65     vector<int>::iterator it;
 66     while(que.size()>=1){
 67         te=que.top();
 68         que.pop();
 69        // printf(" \nu=%d r=%d k=%d\n",te.index,te.d,k);
 70         if(r[te.index]<=k){
 71             k-=r[te.index];
 72             vis[te.index]=1;
 73         }
 74         else{
 75             vis[te.index]=0;
 76             continue;
 77         }
 78         if(ff==0){
 79             ff=1;
 80             printf("%d",te.index);
 81         }
 82         else{
 83             printf(" %d",te.index);
 84         }
 85         for(it=bian[te.index].begin();it!=bian[te.index].end();it++)
 86         {
 87             int y=*it;
 88             r[y]--;
 89             if(r[y]<=k && vis[y]==0){
 90                 nt.index=y;
 91                 nt.d=r[y];
 92                 que.push(nt);
 93                 vis[y]=-1;
 94             }
 95         }
 96     }
 97     printf("\n");
 98 }
 99 
100 void out()
101 {
102 
103 }
104 
105 int main()
106 {
107     //freopen("data.in","r",stdin);
108     //freopen("data.out","w",stdout);
109     //scanf("%d",&T);
110     //for(int cnt=1;cnt<=T;cnt++)
111     //while(T--)
112     while(scanf("%d%d%d",&n,&m,&k)!=EOF)
113     {
114         ini();
115         solve();
116         out();
117     }
118 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM