题意:有N个人,M个优先级a,b表示a优先于b,并且每个人有个编号,使编号越小的点尽可能在序列前部(不是字典序),输出顺序。
思路:首先想的是正向建边的拓扑,但随之写了一组数据给否定了,然后尝试反向建边,发现每次先对序号大的进行处理,然后送入ans数组中得到的就是正确序列。其实可以想得通,因为每次都对序号大的进行处理,它肯定都会在当前所有可处理的点的后面的,所以一路贪心过去即可。
Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 30005;
const int maxm = 100005;
struct node
{
int v, next;
}edge[maxm];
int head[maxn], degree[maxn];
int n, m, no;
vector<int> vt;
priority_queue<int> q;
inline void init()
{
no = 0;
vt.clear();
memset(degree, 0, sizeof degree);
memset(head, -1, sizeof head);
}
int add(int u, int v)
{
int k = head[u];
while(k != -1)
{
if(edge[k].v == v) return 0;
k = edge[k].next;
}
edge[no].v = v;
edge[no].next = head[u];
head[u] = no++;
return 1;
}
void kahn()
{
while(!q.empty())
{
int tp = q.top(); q.pop();
vt.push_back(tp);
int k = head[tp];
while(k != -1)
{
--degree[edge[k].v];
if(!degree[edge[k].v]) q.push(edge[k].v);
k = edge[k].next;
}
}
}
int main()
{
int t, a, b, flag;
scanf("%d", &t);
for(int _ = 1; _ <= t; ++_)
{
scanf("%d %d", &n, &m);
init();
for(int i = 1; i <= m; ++i)
{
scanf("%d %d", &a, &b);
if(add(b, a)) ++degree[a];
}
for(int i = 1; i <= n; ++i)
if(!degree[i]) q.push(i);
kahn(); flag = 0;
for(int i = vt.size()-1; i >= 0; --i)
{
if(flag) printf(" ");
printf("%d", vt[i]); flag = 1;
}
puts("");
}
return 0;
}
对于DFS版拓扑,估计只适用于已知符合拓扑条件然后去求一个任意拓扑序列吧。
继续加油~