题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857
逆序建图,编号大的往前排,拓扑排序,倒序输出。
为什么要这么做呢?
首先这是要求编号小的尽量排在前面,而不是字典序最小(字典序是让前面的编号尽量小,两者对于靠前和编号尽量小的优先级不同)。例如:
1
3 1
3 1
那么字典序最小的话就是 2 3 1,而 1 却应该在 2 的前面,这样正确答案就应该是3 1 2。
怎么办呢?首先把图的有向边全部逆过来然后倒序输出拓扑排序,也是正向拓扑排序的一种方案,那么对于每一次删边之后得到的所有入度为 0 的点,把其添加到优先队列中,编号大的排在前面,倒序输出后就是编号大的排在后面,这样就解决了。
提交的时候有超时问题,原因是过多使用了memset 函数……
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define maxn 30010
using namespace std;
struct Edge
{
int u, v;
Edge(int x, int y):u(x), v(y) {}
};
vector<Edge> edges;
vector<int> G[maxn];
priority_queue<int> Q;
bool operator == (const Edge a, const Edge b)
{
return a.u == b.u && a.v == b.v;
}
int main()
{
int t;
scanf("%d",&t);
while (t > 0)
{
t--;
int into[maxn] = {0};
int List[maxn] = {0};
bool f[maxn] = {0};
int n, m;
scanf("%d%d",&n,&m);
for (int i=0; i<m; i++)
{
int x, y;
scanf("%d%d",&x,&y);
Edge e(y,x);
edges.push_back(e);
G[y].push_back(edges.size()-1);
into[x]++;
}
for (int i=1; i<=n; i++)
if (into[i] == 0)
Q.push(i);
for (int i=0; i<n; i++)
{
int j = Q.top();
Q.pop();
List[i] = j;
f[j] = true;
for (int k=0; k<G[j].size(); k++)
{
into[edges[G[j][k]].v]--;
if (into[edges[G[j][k]].v] == 0 && !f[edges[G[j][k]].v])
Q.push(edges[G[j][k]].v);
}
}
for (int i=n-1; i>0; i--)
printf("%d ",List[i]);
printf("%d\n",List[0]);
for (int i=0; i<=n; i++) G[i].clear();
edges.clear();
while (!Q.empty()) Q.pop();
}
return 0;
}