BZOJ 4010 菜肴制作

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;
}
posted @ 2015-04-22 21:29  lmxyy  阅读(338)  评论(0编辑  收藏  举报