现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。
负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。
那么你就要安排大家的顺序。我们保证一定有解。
Input
然后对于每个测试数据,第一行有两个整数n(1 <= n <= 30000)和m(1 <= m <= 100000),分别表示人数和约束的个数。
然后m行,每行两个整数a和b,表示有一个约束a号必须在b号之前。a和b必然不同。
Output
Sample Input
1 5 10 3 5 1 4 2 5 1 2 3 4 1 4 2 3 1 5 3 5 1 2
Sample Output
1 2 3 4 5
http://vj.hsacm.com/contest/view.action?cid=67#problem/A
其实我觉得蛮有难度的,深搜,链表都试过了,都是写到结尾被否决掉。归根结底是我思路不行。
说说我一开始的思路:先把先后的链构出来,然后发现会有很多这样平行不相关的链,不知道怎么交叉输出。然后想到用拓扑思想逐个变成符合条件输出,但是可能会出现前面遍历过的点因为后面的点删掉而变符合,然后又可以删。然而是继续往下遍历还是找到前面的点深层遍历我没搞清楚(其实这里有个因果关系)。然后我又想到用深搜解决这个问题,然而这样就不能交错输出了。继而又想到了链表。然而写到后来发现进行不下去了。。。
其实我的理解也有错误。应该是以编号优先(比如说4 1/4 1应该输出4 1 2 3而不是2 3 4 1),由这个例子可以知道应该先以编号优先再以约束优先。
正确思路是拓扑+优先队列。这里还有个要拐弯的地方是,队列里的东西在最后输出的时候是反向的(不知道是怎么利用这一点想到思路的,那就让我废话一下来梳理思路好了。。。)
首先拿到很多约束(a在b前),而没有受到约束的点(包括约束放后的点)是可以随意放置的,而有约束的点却必须放在某一些点的前面。那不如把能放后面的点先放后面,这样也能贪心地保证可以满足较多的情况(为什么不正推?因为先以编号优先再以约束优先 )。那么什么样的点适合放后面?肯定是没有约束的点从小到大放后面。那么,当前没有约束的候选点里的最大点一定是确定放最后一个的,而这个点放完了又会导致一些与它约束的点变成了没有约束的点,又成了放后面的候选点,再从候选点里面选一个进行同样的操作。
所以这样子最后输出的点就会变成逆序的了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> x[30005];
vector<int> v;
int y[30005];
struct cmp{
bool operator()(const int &t1,const int &t2){
return t1<t2; //从大到小,与数组规则相反
}
};
int main(){
int t;
scanf("%d",&t);
while(t--){
priority_queue<int,vector<int>,cmp> q;
memset(y,0,sizeof(y));
v.clear();
int n,m,a,b;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
x[i].clear();
while(m--){
scanf("%d%d",&a,&b);
x[b].push_back(a);
y[a]++;
}
for(int i=1;i<=n;++i){
if(y[i]==0){
q.push(i);
}
}
while(!q.empty()){
int w=q.top();
v.push_back(q.top());
q.pop();
for(int i=0;i<x[w].size();++i){
y[x[w][i]]--;
if(y[x[w][i]]==0){
q.push(x[w][i]);
}
}
}
for(int i=v.size()-1;i>0;--i)
printf("%d ",v[i]);
printf("%d\n",v.front());
}
return 0;
}