zoukankan      html  css  js  c++  java
  • BZOJ4010:[HNOI2015]菜肴制作

    我对贪心的理解:https://www.cnblogs.com/AKMer/p/9776293.html

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4010

    对于这道题,比较麻烦的是他要求的并不是完全字典序最小的一个序列,而是满足序号从小到大尽量要靠前。所以这就不能直接每次拓扑排序直接取最小值了,也许较大值取出来后就可以取更小的值了呢。

    比如(2)号菜必须在(5)号菜后面处理,(3)号菜必须在(4)号菜后面处理。那么直接按字典序最小就是(1,4,3,5,2)了,而题意要求的却是(1,5,2,4,3)

    既然这个东西这么麻烦使我们无法很快的判断出哪个值应该放在前面,那么我们就不去想哪个值放在前面了嘛。我们就去想,较大的值是不是应该放在更后面。

    结果发现还真是这样,那么我们就直接倒着做,每次取可取值里最大的值放在后面就行了,拓扑排序加堆优化就(Over)了。

    时间复杂度:(O(nlogn))

    空间复杂度:(O(n))

    代码如下:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1e5+5;
    
    int n,m,tot,cnt,x,y;
    int deg[maxn],ans[maxn];
    int now[maxn],pre[maxn],son[maxn];
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    void clear() {
    	cnt=tot=0;
    	memset(now,0,sizeof(now));
    	memset(deg,0,sizeof(deg));
    }
    
    void add(int a,int b) {
    	pre[++tot]=now[a];
    	now[a]=tot;son[tot]=b;
    	deg[b]++;
    }
    
    struct Heap {
    	int tot;
    	int node[maxn];
    
    	void ins(int x) {
    		node[++tot]=x;
    		int pos=tot;
    		while(pos>1) {
    			if(node[pos]>node[pos>>1])
    				swap(node[pos],node[pos>>1]),pos>>=1;
    			else break;
    		}
    	}
    
    	int pop() {
    		int res=node[1];
    		node[1]=node[tot--];
    		int pos=1,son=2;
    		while(son<=tot) {
    			if(son<tot&&node[son|1]>node[son])son|=1;
    			if(node[son]>node[pos])
    				swap(node[son],node[pos]),pos=son,son=pos<<1;
    			else break;
    		}
    		return res;
    	}
    }T;
    
    void work() {
    	for(int i=1;i<=n;i++)
    		if(!deg[i])T.ins(i);
    	while(T.tot) {
    		int u=T.pop();
    		for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    			if(!(--deg[v]))T.ins(v);
    		ans[++cnt]=u;
    	}
    }//拓扑排序加大根堆优化
    
    void print_ans() {
    	for(int i=n;i>1;i--)
    		printf("%d ",ans[i]);
    	printf("%d
    ",ans[1]);//输出也要倒着
    }
    
    int main() {
    	int T=read();
    	while(T--) {
    		n=read(),m=read();clear();
    		for(int i=1;i<=m;i++)
    			x=read(),y=read(),add(y,x);//y要比x后制作,所以y向x连边
    		work();
    		if(cnt!=n)puts("Impossible!");//cnt不等于n说明有环,就GG了
    		else print_ans();
    	}
    	return 0;
    }
    
  • 相关阅读:
    简单封装万维易源(showapi)ip归属地查询接口
    修改七牛上传域名
    深度探索C++对象模型 个人总结 第四章 Function语意学
    深度探索C++对象模型 个人总结 第三章 Data语意学
    深度探索C++对象模型 个人总结 第二章 构造函数语意学
    深度探索C++对象模型 个人总结 第一章 关于对象
    《More Effective C++》 个人总结
    《Effective C++》个人总结
    C++ Primer第5版 第十九章课后练习答案
    C++ Primer第5版 第十八章课后练习答案
  • 原文地址:https://www.cnblogs.com/AKMer/p/9864909.html
Copyright © 2011-2022 走看看