BZOJ 1194 [HNOI2006]潘多拉的盒子 (图论+拓扑排序+tarjan)

题面:洛谷传送门 BZOJ传送门

标签里三个算法全都是提高组的,然而..这是一道神题

 

我们把这道题分为两个部分解决

1.找出所有咒语机两两之间的包含关系

2.求出咒语机的最长上升序列

 

我们假设咒语机$a,b$满足$a\in b$

如果这个条件不成立,说明存在一个串$S$,$a$能输出,$b$不能输出

一个咒语机能产生的字符串可能是无限长的,直接枚举字符串肯定不行

考虑转化问题

我们构造另外一个图,图中每个点是一个二元组$(x,y)$

我们暴力枚举咒语机$a$中的一个元件$x$,$b$中的一个元件$y$

我们把$(x,y)$分别向$(p_{x,0},p_{y,0}),(p_{x,1},p_{y,1})$连边

如果从$(0,0)$开始,走到了一个节点$(x,y)$,且$x$是$S$的一个输出点,而$y$却不是

说明$a\in b$不成立

因为从$(0,0)$走到$(x,y)$这样一条路径,对于$a,b$来说,是它们都能表示出来的字符串

即$a$中从$0$号元件走到$x$,$b$中从$0$号元件走到$y$,它们走出来的路径表示的字符串相同

而$a$能把它输出,$b$却不能,那么一定不满足$a\in b$

我们解决了第一个部分

 

我们得到了咒语机(点的集合)之间的关系,现在我们要求出它的最长上升序列

拓扑排序裸题吧

然而可能会出现环,即某些咒语机能表示出来的字符串集合相同

用$tarjan$缩点重新建出拓扑图,拓扑排序跑最长路即可

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define N1 2505
  5 #define M1 55
  6 using namespace std;
  7  
  8 struct Graph{
  9 int p[M1][2],out[M1],n,m;
 10 void Read()
 11 {
 12     int i,x;
 13     scanf("%d%d",&n,&m);
 14     for(i=1;i<=m;i++) scanf("%d",&x),out[x+1]=1;
 15     for(i=1;i<=n;i++) scanf("%d%d",&p[i][0],&p[i][1]),p[i][0]++,p[i][1]++;
 16 }    
 17 }g[M1];
 18 struct Edge{
 19 int head[N1],nxt[N1<<1],to[N1<<1],cte;
 20 void ae(int u,int v){ cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
 21 }e,E,N;
 22  
 23 int nt[N1],que[N1],hd,tl,vis[N1],inc[M1];
 24 void init()
 25 {
 26     memset(&e,0,sizeof(e));
 27     memset(nt,0,sizeof(nt)); 
 28     memset(vis,0,sizeof(vis));
 29 }
 30 int solve(Graph &ss,Graph &tt)
 31 {
 32     int i,j,x,v,ans=-2; init();
 33     for(i=1;i<=ss.n;i++) 
 34     for(j=1;j<=tt.n;j++)
 35     {
 36         x=(i-1)*tt.n+j;
 37         v=(ss.p[i][0]-1)*tt.n+tt.p[j][0]; e.ae(x,v);
 38         v=(ss.p[i][1]-1)*tt.n+tt.p[j][1]; e.ae(x,v);
 39         if(ss.out[i]&&!tt.out[j]) nt[x]=1;
 40         if(!ss.out[i]&&tt.out[j]) nt[x]=-1;
 41     }
 42     hd=1,tl=0; que[++tl]=1; vis[1]=1;
 43     while(hd<=tl)
 44     {
 45         x=que[hd++];
 46         if(nt[x])
 47         { 
 48             if(ans==-2) ans=nt[x]; 
 49             else if(ans!=nt[x]) return 0; 
 50         } 
 51         for(j=e.head[x];j;j=e.nxt[j])
 52         {
 53             v=e.to[j]; 
 54             if(!vis[v]) que[++tl]=v, vis[v]=1;
 55         }
 56     }
 57     return ans;
 58 }
 59 int low[M1],dfn[M1],use[M1],stk[M1],tim,tp;
 60 int num[M1],nn,dad[M1],f[M1];
 61 void tarjan(int x,int fa)
 62 {
 63     int j,v;
 64     low[x]=dfn[x]=++tim;
 65     stk[++tp]=x; use[x]=1;
 66     for(j=E.head[x];j;j=E.nxt[j])
 67     {
 68         v=E.to[j]; 
 69         if(v==fa) continue;
 70         if(!dfn[v]){
 71             tarjan(v,x);
 72             low[x]=min(low[x],low[v]);
 73         }else if(use[v]){
 74             low[x]=min(low[x],dfn[v]);
 75         }
 76     }
 77     if(low[x]==dfn[x])
 78     {
 79         nn++;
 80         while(stk[tp]!=x)
 81         {
 82             use[stk[tp]]=0,dad[stk[tp]]=nn;
 83             tp--,num[nn]++;
 84         }
 85         dad[x]=nn, use[x]=0, tp--, num[nn]++;
 86     }
 87 }
 88  
 89 int S;
 90  
 91 int main()
 92 {
 93     scanf("%d",&S);
 94     int i,j,k,s,sx,sy,x,v,ans=0;
 95     for(s=1;s<=S;s++) g[s].Read();
 96     for(sx=1;sx<=S;sx++)
 97     for(sy=sx+1;sy<=S;sy++)
 98     {
 99         k=solve(g[sx],g[sy]);
100         if(!k) continue;
101         if(ans==-2) E.ae(sx,sy), E.ae(sy,sx);
102         else if(k==-1) E.ae(sx,sy);
103         else E.ae(sy,sx);
104     }
105     for(s=1;s<=S;s++)
106         if(!dfn[s]) tarjan(s,-1);
107     for(x=1;x<=S;x++)
108         for(j=E.head[x];j;j=E.nxt[j])
109         {
110             v=E.to[j];
111             if(dad[x]!=dad[v]) 
112                 N.ae(dad[x],dad[v]), inc[dad[v]]++;
113         }
114     hd=1,tl=0;
115     for(i=1;i<=nn;i++) if(!inc[i]) que[++tl]=i;
116     memset(use,0,sizeof(use));
117     while(hd<=tl)
118     {
119         x=que[hd++]; ans=max(ans,f[x]);
120         for(j=N.head[x];j;j=N.nxt[j])
121         {
122             v=N.to[j];
123             f[v]=max(f[v],f[x]+1); inc[v]--;
124             if(!inc[v]) que[++tl]=v;
125         }
126     }
127     printf("%d\n",ans+1);
128 }

 

posted @ 2019-01-22 19:05  guapisolo  阅读(192)  评论(0编辑  收藏  举报