题面:洛谷传送门 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$缩点重新建出拓扑图,拓扑排序跑最长路即可

 #include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 2505
#define M1 55
using namespace std; struct Graph{
int p[M1][],out[M1],n,m;
void Read()
{
int i,x;
scanf("%d%d",&n,&m);
for(i=;i<=m;i++) scanf("%d",&x),out[x+]=;
for(i=;i<=n;i++) scanf("%d%d",&p[i][],&p[i][]),p[i][]++,p[i][]++;
}
}g[M1];
struct Edge{
int head[N1],nxt[N1<<],to[N1<<],cte;
void ae(int u,int v){ cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
}e,E,N; int nt[N1],que[N1],hd,tl,vis[N1],inc[M1];
void init()
{
memset(&e,,sizeof(e));
memset(nt,,sizeof(nt));
memset(vis,,sizeof(vis));
}
int solve(Graph &ss,Graph &tt)
{
int i,j,x,v,ans=-; init();
for(i=;i<=ss.n;i++)
for(j=;j<=tt.n;j++)
{
x=(i-)*tt.n+j;
v=(ss.p[i][]-)*tt.n+tt.p[j][]; e.ae(x,v);
v=(ss.p[i][]-)*tt.n+tt.p[j][]; e.ae(x,v);
if(ss.out[i]&&!tt.out[j]) nt[x]=;
if(!ss.out[i]&&tt.out[j]) nt[x]=-;
}
hd=,tl=; que[++tl]=; vis[]=;
while(hd<=tl)
{
x=que[hd++];
if(nt[x])
{
if(ans==-) ans=nt[x];
else if(ans!=nt[x]) return ;
}
for(j=e.head[x];j;j=e.nxt[j])
{
v=e.to[j];
if(!vis[v]) que[++tl]=v, vis[v]=;
}
}
return ans;
}
int low[M1],dfn[M1],use[M1],stk[M1],tim,tp;
int num[M1],nn,dad[M1],f[M1];
void tarjan(int x,int fa)
{
int j,v;
low[x]=dfn[x]=++tim;
stk[++tp]=x; use[x]=;
for(j=E.head[x];j;j=E.nxt[j])
{
v=E.to[j];
if(v==fa) continue;
if(!dfn[v]){
tarjan(v,x);
low[x]=min(low[x],low[v]);
}else if(use[v]){
low[x]=min(low[x],dfn[v]);
}
}
if(low[x]==dfn[x])
{
nn++;
while(stk[tp]!=x)
{
use[stk[tp]]=,dad[stk[tp]]=nn;
tp--,num[nn]++;
}
dad[x]=nn, use[x]=, tp--, num[nn]++;
}
} int S; int main()
{
scanf("%d",&S);
int i,j,k,s,sx,sy,x,v,ans=;
for(s=;s<=S;s++) g[s].Read();
for(sx=;sx<=S;sx++)
for(sy=sx+;sy<=S;sy++)
{
k=solve(g[sx],g[sy]);
if(!k) continue;
if(ans==-) E.ae(sx,sy), E.ae(sy,sx);
else if(k==-) E.ae(sx,sy);
else E.ae(sy,sx);
}
for(s=;s<=S;s++)
if(!dfn[s]) tarjan(s,-);
for(x=;x<=S;x++)
for(j=E.head[x];j;j=E.nxt[j])
{
v=E.to[j];
if(dad[x]!=dad[v])
N.ae(dad[x],dad[v]), inc[dad[v]]++;
}
hd=,tl=;
for(i=;i<=nn;i++) if(!inc[i]) que[++tl]=i;
memset(use,,sizeof(use));
while(hd<=tl)
{
x=que[hd++]; ans=max(ans,f[x]);
for(j=N.head[x];j;j=N.nxt[j])
{
v=N.to[j];
f[v]=max(f[v],f[x]+); inc[v]--;
if(!inc[v]) que[++tl]=v;
}
}
printf("%d\n",ans+);
}

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

  1. 图论(Tarjan缩点):BZOJ 1194: [HNOI2006]潘多拉的盒子

    1194: [HNOI2006]潘多拉的盒子 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 344  Solved: 181[Submit][Stat ...

  2. BZOJ 1194: [HNOI2006]潘多拉的盒子( BFS + tarjan + dp )

    O(S²)枚举2个诅咒机, 然后O(n²)BFS去判断. 构成一个有向图, tarjan缩点, 然后就是求DAG的最长路.. ------------------------------------- ...

  3. BZOJ 1194: [HNOI2006]潘多拉的盒子 [DP DFA]

    传送门 题意: s个DFA,选出尽量多的自动机a0, a1, a2, . . . , at,使得a1包含a0.a2包 含a1,以此类推.s ≤ 50. DFA的字符集为{0,1},有的节点是输出源,节 ...

  4. 1194: [HNOI2006]潘多拉的盒子

    1194: [HNOI2006]潘多拉的盒子 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 464  Solved: 221[Submit][Stat ...

  5. 1194: [HNOI2006]潘多拉的盒子 - BZOJ

    Description  Input 第一行是一个正整数S,表示宝盒上咒语机的个数,(1≤S≤50).文件以下分为S块,每一块描述一个咒语机,按照咒语机0,咒语机1„„咒语机S-1的顺序描述.每一块的 ...

  6. BZOJ1194: [HNOI2006]潘多拉的盒子(tarjan)

    Description 传说中,有个神奇的潘多拉宝盒.如果谁能打开,便可以拥有幸福.财富.爱情.可是直到真的打开,才发现与之 相随的还有灾难.不幸.其实,在潘多拉制造这个宝盒的时候,设置了一些咒语来封 ...

  7. 【bzoj1194】 HNOI2006—潘多拉的盒子

    http://www.lydsy.com/JudgeOnline/problem.php?id=1194 (题目链接) 题意 给出S个自动机,如果一个自动机u的所有状态是另一个自动机v的状态的子集,那 ...

  8. 【强连通分量】Bzoj1194 HNOI2006 潘多拉的盒子

    Description Sulotion 首先要对每对咒语机建图,判断机器a是否能生成所有机器b生成的 如果跑一个相同的串,最后结束的点b可输出a不可输出,判断就为否 大概就用这种思路,f[x][y] ...

  9. HNOI2006 潘多拉的盒子

    题目描述 题解: 题目的描述比较长,理解起来也有一定难度.仔细读题后我们发现整个任务可以分成两个部分:找出咒语机之间所有的升级关系.求最长升级序列. 1. 求升级关系: 容易看出,咒语机i可以抽象成一 ...

随机推荐

  1. 0419如何利用关系角度看待SQL

    转自http://www.open-open.com/solution/view/1389339225820 十步完全理解SQL   1. SQL 是一种声明式语言 首先要把这个概念记在脑中:“声明” ...

  2. ExtJs之Ext.Model的MemoryProxy

    书上的代码已完全不可参考,只好按知识点从网上查资料一个一个实例 了. <!DOCTYPE html> <html> <head> <title>ExtJ ...

  3. springcloud(一):Spring Cloud

    研究了一段时间Spring Boot了准备向Spring Cloud进发,公司架构和项目也全面拥抱了Spring Cloud.在使用了一段时间后发现Spring Cloud从技术架构上降低了对大型系统 ...

  4. UVA 10187 From Dusk Till Dawn /PC 110907

    不吐槽.. #include <iostream> #include <map> #include <queue> //无语的水题.节哀吧.且这道题不严谨,因为没说 ...

  5. TensorFlow 入门之手写识别CNN 三

    TensorFlow 入门之手写识别CNN 三 MNIST 卷积神经网络 Fly 多层卷积网络 多层卷积网络的基本理论 构建一个多层卷积网络 权值初始化 卷积和池化 第一层卷积 第二层卷积 密集层连接 ...

  6. java中的移位操作

    java中的移位操作仅仅对; a = a << 2; System.out.println(a); System.out.println(Integer.toBinaryString(a) ...

  7. VmBox硬盘容量调整

    硬盘容量修改为15*1024MB. VBoxManage.exe modifyhd "F:\VirtualBox\magiclinux.vdi"   --resize 15360 ...

  8. Linux之convert命令【转】

    本文转载自:http://zlb1986.iteye.com/blog/778054 转载: 强大的convert命令 convert命令可以用来转换图像的格式,支持JPG, BMP, PCX, GI ...

  9. php与java语法的区别

    php与java语法的区别 个人觉得在学习语言时,可以通过比较来进行学习.由于长时间写java代码,对java的基本语法还算熟悉,现在转学php,就php中基本语法与java基本语法差异进行比较. 1 ...

  10. 深入解析Dropout——基本思想:以概率P舍弃部分神经元,其它神经元以概率q=1-p被保留,舍去的神经元的输出都被设置为零

    深度学习网络大杀器之Dropout——深入解析Dropout  转自:https://yq.aliyun.com/articles/68901 摘要: 本文详细介绍了深度学习中dropout技巧的思想 ...