HNOI 2015 菜肴制作
HNOI 2015 菜肴制作
题目链接:HNOI2015 菜肴制作
显然的拓扑排序,一个很明显的想法是建图跑拓扑排序然后用小根堆来替换队列。但是这个想法明显有误,举个例子,现在我们能做 \(3,4\),而 \(4\) 对 \(1\) 的制作有利,\(3\) 对 \(1\) 的制作无益,那么我们应该先做 \(4\) 而不是 \(3\)。那么我们可以倒着思考,我们将原图的边的方向取反,然后用大根堆跑一趟拓扑排序,相当于我们倒着填一个顺序,当前入度为 \(0\) 的点肯定有一个是要放在当前位置上的,那么我们就让大的编号的点放在后面。接下来就是一个拓扑排序的模板。时间复杂度 \(O(n+m)\)。
代码如下:
#include<bits/stdc++.h>
#define ls(k) (k<<1)
#define rs(k) (k<<1|1)
using namespace std;
const int MAXN = 1e5+5;
int n,m,ans[MAXN],in[MAXN];
vector <int> e[MAXN];
bool topo()
{
priority_queue <int> q;
for(int i=1;i<=n;++i)
if(!in[i]) q.push(i);
int cnt=0;
while(!q.empty())
{
int p=q.top();
q.pop();
ans[++cnt]=p;
for(int i=0;i<e[p].size();++i)
{
int to=e[p][i];
in[to]--;
if(!in[to]) q.push(to);
}
}
for(int i=1;i<=n;++i)
if(in[i]) return true;
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) e[i].clear();
memset(in,0,sizeof in);
for(int i=1;i<=m;++i)
{
int u,v;
scanf("%d %d",&u,&v);
e[v].push_back(u);
in[u]++;
}
if(topo()) printf("Impossible!\n");
else
{
for(int i=n;i>=1;--i) printf("%d ",ans[i]);
printf("\n");
}
}
return 0;
}
总结:拓扑排序好题。
路漫漫其修远兮,吾将上下而求索。