Description
知名美食家小A被邀请至ATM 大酒店,为其品评菜肴。
ATM酒店为小A准备了(N)道菜肴,酒店按照为菜肴预估的质量从高到低给予(1)到(N)的顺序编号,预估质量最高的菜肴编号为(1)。由于菜肴之间口味搭配的问题,某些菜肴必须在另一些菜肴之前制作,具体的,一共有(M)条形如“(i)号菜肴‘必须’先于(j)号菜肴制作”的限制,我们将这样的限制简写为(< i,j>)。现在,酒店希望能求出一个最优的菜肴的制作顺序,使得小 A能尽量先吃到质量高的菜肴:也就是说,((1))在满足所有限制的前提下,(1)号菜肴“尽量”优先制作;((2))在满足所有限制,(1)号菜肴“尽量”优先制作的前提下,(2)号菜肴“尽量”优先制作;((3))在满足所有限制,(1)号和(2)号菜肴“尽量”优先的前提下,(3)号菜肴“尽量”优先制作;((4))以此类推。
例(1):共(4)道菜肴,两条限制(<3,1>,<4,1>),那么制作顺序是(3,4,1,2)。
例(2):共(5)道菜肴,两条限制(<5,2>,<4,3>),那么制作顺序是(1,5,2,4,3)。例(1)里,首先考虑(1),因为有限制(<3,1>)和(<4,1>),所以只有制作完(3)和(4)后才能制作(1),而根据((3)),(3)号又应“尽量”比(4)号优先,所以当前可确定前三道菜的制作顺序是(3,4,1);接下来考虑(2),确定最终的制作顺序是(3,4,1,2)。例(2)里,首先制作(1)是不违背限制的;接下来考虑(2)时有(<5,2>)的限制,所以接下来先制作(5)再制作(2);接下来考虑(3)时有(<4,3>)的限制,所以接下来先制作(4)再制作(3),从而最终的顺序是(1,5,2,4,3)。现在你需要求出这个最优的菜肴制作顺序。无解输出“Impossible!” (不含引号,首字母大写,其余字母小写)
Input
第一行是一个正整数(D),表示数据组数。
对于每组数据:
第一行两个用空格分开的正整数(N)和(M),分别表示菜肴数目和制作顺序限制的条目数。
接下来(M)行,每行两个正整数(x,y),表示“(x)号菜肴必须先于(y)号菜肴制作”的限制。(注意:(M)条限制中可能存在完全相同的限制)
Output
输出文件仅包含(D)行,每行(N)个整数,表示最优的菜肴制作顺序,或者”Impossible!”表示无解(不含引号)。
Sample Input
3
5 4
5 4
5 3
4 2
3 2
3 3
1 2
2 3
3 1
5 2
5 2
4 3
Sample Output
1 5 3 4 2
Impossible!
1 5 2 4 3
Hint
(N,M le 100000,D le 3)
Solution
考试的时候打的(70')做法,即从小到大依次确定可以放置的最前的位置。复杂度(O(n^{2}))。
正解的做法很简单,却并不好像,好像跟NOI2010航空管制很像。
将图反连,我们从小到大确定每个最前的位置,即在反top序中从小到大最后的位置。我们还是topsort,只是每次取出的点是所有入度为(0)的标号最大的点。这要的贪心 ,我们就可以保证编号小的尽可能的在后面。最后将top序反着输出即可。
#include<iostream>
#include<set>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
#define maxn (100010)
int d[maxn],side[maxn],next[maxn*2],toit[maxn*2],ans[maxn],cnt,n,m;
inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; ++d[b]; }
struct cmp { inline bool operator ()(const int &a,const int &b) { return a>b; } };
set <int,cmp> S;
inline bool topsort()
{
int tot = 0;
for (int i = 1;i <= n;++i) if (!d[i]) S.insert(i);
while (!S.empty())
{
int now = *S.begin(); S.erase(S.begin());
ans[++tot] = now;
for (int i = side[now];i;i = next[i]) if (!--d[toit[i]]) S.insert(toit[i]);
}
return tot == n;
}
int main()
{
freopen("4010.in","r",stdin);
freopen("4010.out","w",stdout);
int T; scanf("%d",&T);
while (T--)
{
scanf("%d %d",&n,&m);
for (int i = 1,a,b;i <= m;++i) scanf("%d %d",&a,&b),add(b,a);
if (!topsort()) printf("Impossible!");
else for (int i = n;i;--i) printf("%d ",ans[i]);
puts("");
memset(side,0,4*(n+1));
memset(d,0,4*(n+1));
cnt = 1;
}
fclose(stdin); fclose(stdout);
return 0;
}