洛谷P3243 [HNOI2015]菜肴制作 (拓扑排序/贪心)
作者:互联网
这道题的贪心思路可真是很难证明啊......
对于<i,j>的限制(i必须在j之前),容易想到topsort,每次在入度为0的点中选取最小的。但这种正向找是错误的,题目要求的是小的节点尽量往前,并不是字典序最小。<i,j>中i肯定大于j,这样建的图中小的节点是靠后的,当然不行;那我们考虑反向建图,那么小的节点就靠前了,因为是反向建图,我们要让大的节点尽量往前,最后倒着输出,那么小的节点自然就靠前了。
有种重要的思路就是正的不行那就反着来,考场上实在不能证明,那就多举几个例子看是否正确。
建立大根堆,再反向图中优先选择大的节点。
有环时就是无解的情况,ans节点数量小于n。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+5; 4 int T,n,m,in[N]; 5 vector<int> a[N],ans; 6 7 int main(){ 8 scanf("%d",&T); 9 while(T--){ 10 memset(in,0,sizeof(in));ans.clear(); 11 for(int i=0;i<N;i++) a[i].clear(); 12 scanf("%d%d",&n,&m); 13 for(int i=1;i<=m;i++){ 14 int x,y;scanf("%d%d",&x,&y); 15 a[y].push_back(x);in[x]++; 16 } 17 priority_queue<int> q;//大根堆 18 for(int i=1;i<=n;i++) 19 if(!in[i]) q.push(i);//入度为0的点加入 20 while(!q.empty()){ 21 int v=q.top();q.pop(); 22 ans.push_back(v); 23 for(int i=0;i<a[v].size();i++){ 24 in[a[v][i]]--; 25 if(!in[a[v][i]]) q.push(a[v][i]); 26 } 27 } 28 if(ans.size()!=n) puts("Impossible!"); 29 else{ 30 reverse(ans.begin(),ans.end()); 31 for(int i=0;i<ans.size();i++) printf("%d ",ans[i]); 32 puts(""); 33 } 34 } 35 return 0; 36 }
标签:大根堆,洛谷,int,建图,反向,HNOI2015,ans,P3243,节点 来源: https://www.cnblogs.com/yhxnoerror/p/16438911.html