zoukankan      html  css  js  c++  java
  • BZOJ4010 [HNOI2015]菜肴制作[拓扑排序+贪心]

    其实有些题真的是,即使翻看了题解,也可以解释一二原因,也并不能对这种做法有深深的认同感。。


    因为题意说的是让序号小的优先在拓扑序中向左靠,也就是说,比如1号会被前面很多大序号的节点“堵住”,但是仍要优先让他先出来,所以这时候按字典序最小来做拓扑是不对的。。`````

    反过来考虑:

    引理:对于一张DAG,其任意一个拓扑序的倒序和这张反向的DAG的拓扑序一一对应。

    证明:不会证明。对于出现在原拓扑序末尾的一段,一定是没有出度的节点,那么反图中,他们没有入度,所以可以出现在拓扑序开头,而末尾再向前一段的点(假设为$x$)是有出度的,且指向这些没有出度的点,这在反图中就对应了没有入度的点删掉后,继续选择$x$为零入度点。以此类推。所以正拓扑序反序和反图拓扑序对应,同理,后者也与前者对应。

    反正这个是超有道理的啦(っ ̄▽ ̄)っ。

    于是,建一张反的DAG,并且采用字典序从大到小的方法拓扑排序。为什么这样做?因为,首先反向的拓扑序是和正向拓扑序等价的,这是前提。然后,在所有入度为0的点里,我们要选择最大的,因为,如果我们先选择了小序号的放在后面,那么明显他应该再往左靠,也就是说,小数字比大数字向左靠的优先级高。这样,一个拓扑序中,大数尽量放后面,“让”给小数,让小数尽量靠左。这样的贪心就是对的。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=1e5+7;
    24 int T,n,m,flag;
    25 struct thxorz{int nxt,to;}G[N];
    26 int Head[N],tot;
    27 inline void Addedge(int x,int y){G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot;}
    28 #define y G[j].to
    29 //int dfn[N],low[N],cnt,stk[N],instk[N],Top;
    30 //void tarjan(int x){
    31 //    dfn[x]=low[x]=++cnt,stk[++Top]=x,instk[x]=1;
    32 //    for(register int j=Head[x];j;j=G[j].nxt){
    33 //        if(!dfn[y])tarjan(y),MIN(low[x],low[y]);
    34 //        else if(instk[y])MIN(low[x],dfn[y]);
    35 //    }
    36 //    if(dfn[x]==low[x]){
    37 //        int tmp,cnt=0;
    38 //        do instk[tmp=stk[Top--]]=0,++cnt;while(tmp^x);
    39 //        if(cnt>1)flag=1;
    40 //    }
    41 //}
    42 int ans[N],r,deg[N];
    43 priority_queue<int> pq;
    44 inline void toposort(){
    45     for(register int i=1;i<=n;++i)if(!deg[i])pq.push(i);
    46     while(!pq.empty()){
    47         ans[++r]=pq.top();pq.pop();
    48         for(register int j=Head[ans[r]];j;j=G[j].nxt)
    49             if(!(--deg[y]))pq.push(y);
    50     }
    51 }
    52 #undef y
    53 
    54 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    55     read(T);while(T--){
    56         read(n),read(m);
    57         flag=tot=r=0;mst(Head),mst(deg);//mst(dfn),mst(low);
    58         for(register int i=1,x,y;i<=m;++i)read(x),read(y),Addedge(y,x),++deg[x];
    59 //        for(register int i=1;i<=n;++i)if(!dfn[i])Top=0,tarjan(i);
    60 //        if(flag){puts("Impossible!");continue;}
    61         toposort();
    62         if(r<n){puts("Impossible!");continue;}
    63         for(register int i=n;i;--i)printf("%d ",ans[i]);puts("");
    64     }
    65     return 0;
    66 }
         View     Code     

    总结:正向不便不妨建反图考虑。然而还是个套路、

  • 相关阅读:
    【MM系列】SAP 关于物料间的替代问题
    【MM系列】SAP MM模块-配置PO的创建时间
    为什么需要分布式配置中心?
    基于Redis的Spring cache 缓存介绍
    史上最全面的Spring-Boot-Cache使用与整合
    负载均衡
    分布式架构的演进
    9种高性能可用高并发的技术架构
    微服务写的最全的一篇文章
    Java设计模式——合成/聚合复用原则
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11717868.html
Copyright © 2011-2022 走看看