NC20115 [HNOI2015]菜肴制作
题目链接
关键点:
1、题目要求在给定某些菜品的先后顺序下,并且满足号小的尽量在前的最优顺序
2、对于某些菜品有先后顺序,这就很容易想到拓扑排序,对于有先后顺序的两道菜,就将其连边。首先第一道菜是必要最先做的,那么就从1一直往前找入度为0的点,且如果有并排的选择时先做号小的。以此类推求2所连接的入度为0的点。。。
3、我们可以倒过来,先选择入度为0,且序号最大的点,然后继续更新入度,再选最大的,最后再将其反过来输出。
完整代码:
# include <bits/stdc++.h>
using namespace std;
struct ty{
int t, next;
}edge[100000+10];
int d, n, m, cnt;
int in[100000+10];
int head[100000+10], ans[100000+10];
void addedge(int x, int y)
{
edge[++cnt].t = y;
edge[cnt].next = head[x];
head[x] = cnt;
}
priority_queue<int>q;//最大堆
int tuopu()
{
while (!q.empty()) q.pop();
for (int i=1; i<=n; i++)
{
if (in[i] == 0)
q.push(i);
}
int num = 0;
while (!q.empty())
{
int x = q.top();
q.pop();
ans[++num] = x;
for (int i=head[x]; i!=-1; i=edge[i].next)
{
int t = edge[i].t;
in[t]--;
if (in[t] == 0)
q.push(t);
}
}
if (num<n)
return 0;
else
return 1;
}
int main()
{
cin>>d;
while (d--)
{
cin>>n>>m;
cnt = 0;
memset(head, -1, sizeof(head));
memset(in, 0, sizeof(in));
for (int i=1; i<=m; i++)
{
int x, y;
cin>>x>>y;
addedge(y, x);
in[x]++;
}
if (tuopu())
{
for (int i=n; i>=1; i--)
cout<<ans[i]<<" ";
cout<<endl;
}
else
cout<<"Impossible!"<<endl;
}
return 0;
}