DZY Loves Topological Sorting
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1064 Accepted Submission(s): 327
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
(u→v)
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.
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. (
TestCase≤5
)
The first line, three integers n,m,k(1≤n,m≤105,0≤k≤m) .
Each of the next m lines has two integers: u,v(u≠v,1≤u,v≤n) , representing a direct edge (u→v) .
The first line, three integers n,m,k(1≤n,m≤105,0≤k≤m) .
Each of the next m lines has two integers: u,v(u≠v,1≤u,v≤n) , representing a direct edge (u→v) .
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 2HintCase 1. Erase the edge (2->3),(4->5). And the lexicographically largest topological ordering is (5,3,1,2,4).
解题思路:
因为我们要求最后的拓扑序列字典序最大,所以一定要贪心地将标号越大的点越早入队。我们定义点i的入度为di。假设当前还能删去k条边, 那么我们一定会把当前还没入队的di≤k的最大的i找出来,把它的di条入边都删掉,然后加入拓扑序列。可以证明,这一定是最优的。具体实 现可以用线段树维护每个位置的di,在线段树上二分可以找到当前还没入队的di≤k的最大的i。于是时间复杂度就是O((n+m)logn).
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> using namespace std; const int maxn = 100005; const int inf = 0x3f3f3f3f; struct Seg { int l,r,Min; //Min表示在区间[l,r]上的最小入度 }tree[maxn<<2]; struct Edge { int to,next; }edge[maxn]; int n,m,k,cnt,head[maxn]; int ind[maxn],res[maxn]; void addedge(int u,int v) { edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void build(int rt,int l,int r) { tree[rt].l = l, tree[rt].r = r; if(tree[rt].l == tree[rt].r) { tree[rt].Min = ind[l]; return; } int mid = (l + r) >> 1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); tree[rt].Min = min(tree[rt<<1].Min,tree[rt<<1|1].Min); } void update(int rt,int pos) { if(tree[rt].l == tree[rt].r) { tree[rt].Min--; return; } int mid = (tree[rt].l + tree[rt].r) >> 1; if(pos <= mid) update(rt<<1,pos); else update(rt<<1|1,pos); tree[rt].Min = min(tree[rt<<1].Min,tree[rt<<1|1].Min); } int query(int rt,int k) { if(tree[rt].l == tree[rt].r) { tree[rt].Min = inf; return tree[rt].l; } int ans; if(tree[rt<<1|1].Min <= k) ans = query(rt<<1|1,k); else ans = query(rt<<1,k); tree[rt].Min = min(tree[rt<<1].Min,tree[rt<<1|1].Min); return ans; } int main() { int u,v; while(scanf("%d%d%d",&n,&m,&k)!=EOF) { cnt = 0; memset(head,-1,sizeof(head)); memset(ind,0,sizeof(ind)); for(int i = 1; i <= m; i++) { scanf("%d%d",&u,&v); addedge(u,v); ind[v]++; } build(1,1,n); for(int i = 1; i <= n; i++) { int u = query(1,k); printf(i==n?"%d\n":"%d ",u); k -= ind[u]; ind[u] = 0; for(int j = head[u]; j != -1; j = edge[j].next) { int v = edge[j].to; if(ind[v] > 0) { ind[v]--; update(1,v); } } } } return 0; }