题目描述:给定一个DAG,求出允许移除最多K条边后的字典序最大的拓扑序列。
思路:线段树,每次找入度不超过K的最大编号的顶点,将此顶点从图中移除,重复操作n次即可得到结果。
吐槽:当时打BC的时候写出了一个直接贪心+拓扑排序的复杂度为O(n)的错误代码(当时还没有意识到是错误代码),交到hdu oj上居然给过了,后来上西方文化的时候和csc得瑟,说那个题我300+ms就给过了,在best solutions里面Rank 1,复杂度还是O(n)的,然后和csc说了我的想法以后才发现这思路TM根本就不对啊,航电的数据有点水吧!后来才改用线段树!
附超快-错误-可AC代码入下:
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 using namespace std; 7 8 priority_queue<int> q; 9 const int N = 111111; 10 bool mark[N]; 11 int in[N]; 12 int head[N]; 13 int ans[N], index; 14 int n, m, k, e; 15 16 struct Edge 17 { 18 int v, next; 19 } edge[N]; 20 21 void addEdge( int u, int v ) 22 { 23 edge[e].v = v; 24 edge[e].next = head[u]; 25 head[u] = e; 26 e++; 27 } 28 29 void init() 30 { 31 e = 0; 32 index = 0; 33 memset( in, 0, sizeof(in) ); 34 memset( head, -1, sizeof(head) ); 35 memset( mark, false, sizeof(mark) ); 36 while ( !q.empty() ) 37 { 38 q.pop(); 39 } 40 } 41 42 int main () 43 { 44 while ( scanf("%d%d%d", &n, &m, &k) != EOF ) 45 { 46 init(); 47 for ( int i = 1; i <= m; i++ ) 48 { 49 int u, v; 50 scanf("%d%d", &u, &v); 51 in[v]++; 52 addEdge( u, v ); 53 } 54 for ( int i = n; i > 0 && k > 0; i-- ) 55 { 56 if ( k >= in[i] ) 57 { 58 k -= in[i]; 59 in[i] = 0; 60 ans[index++] = i; 61 for ( int u = head[i]; u != -1; u = edge[u].next ) 62 { 63 int v = edge[u].v; 64 in[v]--; 65 } 66 mark[i] = true; 67 } 68 } 69 for ( int i = 1; i <= n; i++ ) 70 { 71 if ( in[i] == 0 && mark[i] == false ) 72 { 73 q.push(i); 74 } 75 } 76 while ( !q.empty() ) 77 { 78 int tmp = q.top(); 79 q.pop(); 80 ans[index++] = tmp; 81 for ( int u = head[tmp]; u != -1; u = edge[u].next ) 82 { 83 int v = edge[u].v; 84 in[v]--; 85 if ( in[v] == 0 ) 86 { 87 q.push(v); 88 } 89 } 90 } 91 for ( int i = 0; i < index - 1; i++ ) 92 { 93 printf("%d ", ans[i]); 94 } 95 printf("%d\n", ans[index - 1]); 96 } 97 return 0; 98 }
附正确线段树代码如下:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 100001; 7 const int INF = 9999999; 8 int in[N]; 9 int head[N]; 10 int n, m, k, e; 11 12 int min( int a, int b ) 13 { 14 return a < b ? a : b; 15 } 16 17 struct Edge 18 { 19 int v, next; 20 } edge[N]; 21 22 void addEdge( int u, int v ) 23 { 24 edge[e].v = v; 25 edge[e].next = head[u]; 26 head[u] = e++; 27 } 28 29 struct Node 30 { 31 int l, r, in; 32 } node[N * 3]; 33 34 void build( int i, int l, int r ) 35 { 36 node[i].l = l, node[i].r = r; 37 if ( l == r ) 38 { 39 node[i].in = in[l]; 40 return ; 41 } 42 int mid = l + r >> 1; 43 build( i << 1, l, mid ); 44 build( i << 1 | 1, mid + 1, r ); 45 node[i].in = min( node[i << 1].in, node[i << 1 | 1].in ); 46 return ; 47 } 48 49 void update( int i, int pos ) 50 { 51 if ( node[i].l == node[i].r ) 52 { 53 node[i].in = in[pos]; 54 return ; 55 } 56 int mid = node[i].l + node[i].r >> 1; 57 if ( pos <= mid ) 58 { 59 update( i << 1, pos ); 60 } 61 else 62 { 63 update( i << 1 | 1, pos ); 64 } 65 node[i].in = min( node[i << 1].in, node[i << 1 | 1].in ); 66 return ; 67 } 68 69 int query( int i ) 70 { 71 while ( node[i].l != node[i].r ) 72 { 73 if ( k >= node[i << 1 | 1].in ) 74 { 75 i = i << 1 | 1; 76 } 77 else 78 { 79 i = i << 1; 80 } 81 } 82 return node[i].l; 83 } 84 85 void init() 86 { 87 e = 0; 88 memset( head, -1, sizeof(head) ); 89 memset( in, 0, sizeof(in) ); 90 } 91 92 int main () 93 { 94 while ( scanf("%d%d%d", &n, &m, &k) != EOF ) 95 { 96 init(); 97 while ( m-- ) 98 { 99 int u, v; 100 scanf("%d%d", &u, &v); 101 addEdge( u, v ); 102 in[v]++; 103 } 104 build( 1, 1, n ); 105 for ( int i = 0; i < n - 1; i++ ) 106 { 107 int t = query(1); 108 printf("%d", t); 109 if ( i < n - 1 ) putchar(‘ ‘); 110 k -= in[t]; 111 in[t] = INF; 112 update( 1, t ); 113 for ( int u = head[t]; u != -1; u = edge[u].next ) 114 { 115 int v = edge[u].v; 116 if ( in[v] == INF ) continue; 117 in[v]--; 118 update( 1, v ); 119 } 120 } 121 printf("%d\n", query(1)); 122 } 123 return 0; 124 }
说明:用g++交不一定能过,最好挑个交题的人比较少的时候,c++妥妥的。
时间: 2024-10-30 12:23:44