Input
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; }