问题描述
一张有向图的拓扑序列是图中点的一个排列,满足对于图中的每条有向边
(u→v)
从
u
到
v
,都满足
u
在排列中出现在
v
之前。
现在,DZY有一张有向无环图(DAG)。你要在最多删去
k
条边之后,求出字典序最大的拓扑序列。
输入描述
输入有多组数据。 (
TestCase≤5
)
第一行,三个正整数
n,m,k(1≤n,m≤105,0≤k≤m)
.
接下来
m
行,每行两个正整数
u,v(u≠v,1≤u,v≤n)
, 代表一条有向边
(u→v)
.
输出描述
对于每组测试数据,输出一行字典序最大的拓扑序列。
输入样例
5 5 2
1 2
4 5
2 4
3 4
2 3
3 2 0
1 2
1 3
输出样例
5 3 1 2 4
1 3 2
Hint
数据1. 删除(2->3),(4->5)两条边,可以得到字典序最大的拓扑序列:(5,3,1,2,4).
方法一:使用邻接表存储边
#include <bits/stdc++.h>
using namespace std;
#define maxn 100000 + 10
#define INF 0x7ffffff
#define Lson L, mid, root<<1
#define Rson mid+1, R, root<<1|1
int Min[maxn<<2];
int deg[maxn];
int n, m, k, cnt, num;
int head[maxn];
vector<int> vec;
///先明确是利用线段树查询与维护每个点的入度
struct Edge
{
int v;
int next;
} edge[maxn];
void init()
{
num = 0;
cnt = 0;
memset(head, -1, sizeof(head));
memset(deg, 0, sizeof(deg));
vec.clear();
int u, v;
for(int i=0; i<m; i++)
{
cin>>u>>v;
deg[v]++;
edge[cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
}
void Pushup(int root)
{
Min[root] = min(Min[root<<1] , Min[root<<1|1]);
}
void Bulid(int L, int R, int root)
{
if(L == R)
{
Min[root] = deg[++num];
return;
}
int mid = (L+R)>>1;
Bulid(Lson);
Bulid(Rson);
Pushup(root);
}
void Update(int q, int Deg, int L, int R, int root)
{
if(L == R)
{
Min[root] = Deg;
return ;
}
int mid = (L+R)>>1;
if(q <= mid) Update(q, Deg, L, mid, root<<1);
else Update(q, Deg, mid+1, R, root<<1|1);
Pushup(root);
}
///查询Min值不大于k的节点
int Query(int L, int R, int root)
{
if(L==R && Min[root]<=k) return L;
int mid = (L+R)>>1;
if(Min[root<<1|1] <= k)
return Query(Rson);
else return Query(Lson);
}
void topo()
{
for(int i=1; i<=n; i++)
{
int id = Query(1, n, 1);
vec.push_back(id);
k -= deg[id];
deg[id] = INF;
Update(id, INF, 1, n, 1);
for(int j=head[id]; j!=-1; j=edge[j].next)
{
int v = edge[j].v;
deg[v]--;
Update(v, deg[v], 1, n, 1);
}
}
}
int main()
{
while(~scanf("%d%d%d", &n, &m, &k))
{
init();
Bulid(1, n, 1);
topo();
for(int i=0; i<vec.size(); i++)
{
cout<<vec[i];
if(i != vec.size()-1) cout<<" ";
else cout<<endl;
}
}
return 0;
}
方法二:使用vector存储边
#include <bits/stdc++.h>
using namespace std;
#define maxn 100000 + 10
#define INF 0x7ffffff
#define root 1, n, 1
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
int t, k, n, m;
int deg[maxn];
int Min[maxn<<2];
vector<int> G[maxn];
vector<int> vec;
void Pushup(int rt)
{
Min[rt] = min(Min[rt<<1] , Min[rt<<1|1]);
}
void Bulid(int L, int R, int rt)
{
if(L == R)
{
Min[rt] = deg[++t];
return ;
}
int mid = (L+R)>>1;
Bulid(Lson);
Bulid(Rson);
Pushup(rt);
}
void Update(int q, int deg, int L, int R, int rt)
{
if(L == R)
{
Min[rt] = deg;
return;
}
int mid = (L+R)>>1;
if(q <= mid) Update(q, deg, Lson);
else Update(q, deg, Rson);
Pushup(rt);
}
int Query(int L, int R, int rt)
{
if(L==R && Min[rt]<=k) return L;
int mid = (L+R)>>1;
if(Min[rt<<1|1] <= k)
return Query(Rson);
else return Query(Lson);
}
void init()
{
t = 0;
vec.clear();
memset(deg, 0,sizeof(deg));
for(int i=1; i<=n; i++)
G[i].clear();
int u, v;
for(int i=0; i<m; i++)
{
cin>>u>>v;
G[u].push_back(v);
deg[v]++;
}
}
void topo()
{
for(int i=1; i<=n; i++)
{
int id = Query(root);
vec.push_back(id);
k -= deg[id];
deg[id] = INF;
Update(id, INF, root);
for(int j=0; j<G[id].size(); j++)
{
int v = G[id][j];
deg[v]--;
Update(v, deg[v], root);
}
}
}
int main()
{
while(~scanf("%d%d%d", &n, &m, &k))
{
init();
Bulid(root);
topo();
for(int i=0; i<vec.size(); i++)
{
cout<<vec[i];
if(i != vec.size()-1) cout<<" ";
else cout<<endl;
}
}
return 0;
}