[BZOJ4010]HNOI2015菜肴制作|拓扑排序+堆

一开始看成字典序最小。。后来想到不对又YY了一种奇怪的方法,不过还是错的。。

    正解是倒着来,边都倒着加,然后求一个字典序最大的拓扑序,反过来就是答案了。。一开始想不通为什么是这样,仔细想想应该没错。。如果没有选最大的,就让一个更小的放在了后面,而它本可以在更前的,所以一定要选最大的。。感觉和NOI2009变换序列的思路有点像,倒过来把要先满足的放到后面它自然就会满足了。。

#include<cstdio>
#include<iostream>
#include<memory.h>
#define N 100005
using namespace std;
struct edge{
	int e,next;
}ed[N];
int T,n,m,i,j,ne,s,e,nd,heap[N],in[N],u[N],a[N],ans[N];
bool f;
void add(int s,int e)
{
	ed[++ne].e=e;ed[ne].next=a[s];a[s]=ne;
}
bool dfs(int x)
{
	u[x]=-1;
	bool f=true;
	for (int j=a[x];j;j=ed[j].next)
	{
		if (u[ed[j].e]==-1) return false;
		else if (u[ed[j].e]==0) f=f&&dfs(ed[j].e);
	}
	u[x]=1;
	return f;
}
void up(int x)
{
	while (x>1&&heap[x]>heap[x>>1]) swap(heap[x],heap[x>>1]),x>>=1;
}
void ins(int x)
{
	heap[++nd]=x;
	up(nd);
}
void del()
{
	heap[1]=heap[nd--];
	int x=1;
	while (x*2<=nd)
	{
		x<<=1;
		if (x<nd&&heap[x+1]>heap[x]) x++;
		if (heap[x]>heap[x>>1]) swap(heap[x],heap[x>>1]);else break;
	}
}
int main()
{
	freopen("dishes.in","r",stdin);
//	freopen("dishes.out","w",stdout);
	scanf("%d",&T);
	while (T--)
	{
		scanf("%d%d",&n,&m);
		for (i=1;i<=n;i++) a[i]=0,in[i]=0,u[i]=0;
		ne=0;
		for (i=1;i<=m;i++)
		{
			scanf("%d%d",&s,&e);
			add(e,s);in[s]++;
		}
		f=true;
		for (i=1;i<=n;i++)
			if (!u[i]) f=f&&dfs(i);
		if (!f)
		{
			printf("Impossible!\n");
			continue;
		}
		nd=0;
		for (i=1;i<=n;i++)
			if (!in[i]) ins(i);
		for (i=n;i;i--)
		{
			ans[i]=heap[1];
			del();
			for (j=a[ans[i]];j;j=ed[j].next)
				if (--in[ed[j].e]==0) ins(ed[j].e);
		}
		for (i=1;i<=n;i++) printf("%d ",ans[i]);printf("\n");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值