codeforce E - Minimal Labels+hdu 4857
两个题目的意思差不多 都是希望得出的拓扑序如果有多种 要求输出字典序小的情况
这里引用一个大佬的博客 关于为什么不能直接建图然后用小根堆解决这个问题(http://blog.csdn.net/rgnoH/article/details/75253355 : 出处)
再解答一个小问题:
主要是在和六号@Mogician_Evian 交流之后想到的:这道题可以用小根堆做吗?
看起来可以!
可能的操作是:
1.题目中说什么,就怎么连边,并记录入度。
2.执行Topsort标准操作,压入小根堆中。 此时从1到N,依次给取出的堆顶元素进行编号。
可能的分析方法和上面的是类似的。
然而并不能!
为什么?看看这一组数据:
3 1
3 1
正解应该是
2 3 1
然而小根堆会输出
3 1 2
为什么?
我们要的并不是让新编号小的数尽量靠前,而是让答案数组靠前的数尽量小!
小根堆讨论就只是让新编号小的数尽量靠前了。
豁然开朗!
hdu 4857 ac代码:
#include <cstdio> #include <iostream> #include <cstring> #include <queue> #include <algorithm> using namespace std; int in[200001]; int mark[200001]; vector<int > edge[200001]; int n,m; /* struct node { int x; int point; bool operator <(node a,node b) { return a.point > b.point; } }; */ void init() { for(int i=0; i<=n; i++) { in[i]=0; edge[i].clear(); } } void topo() { priority_queue<int,vector<int>,less<int> >q; //大根堆 for(int i=1; i<=n; i++) { if(in[i]==0) q.push(i); } int ret=n; while(!q.empty()) { int now=q.top(); q.pop(); mark[ret--]=now; for(int i=0; i<edge[now].size(); i++) { int temp=edge[now][i]; in[temp]--; if(in[temp]==0) q.push(temp); } } } int main() { int t; cin>>t; while(t--) { cin>>n>>m; init(); for(int i=1; i<=m; i++) { int a,b; scanf("%d %d",&a,&b); edge[b].push_back(a); in[a]++; } topo(); cout<<mark[1]; for(int i=2; i<=n; i++) cout<<' '<<mark[i]; cout<<endl; } return 0; }