其他分享
首页 > 其他分享> > 洛谷P3243 [HNOI2015]菜肴制作 (拓扑排序/贪心)

洛谷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