zoukankan      html  css  js  c++  java
  • 【BZOJ-1194】潘多拉的盒子 拓扑排序 + DP

    1194: [HNOI2006]潘多拉的盒子

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 456  Solved: 215
    [Submit][Status][Discuss]

    Description

     

    Input

    第一行是一个正整数S,表示宝盒上咒语机的个数,(1≤S≤50)。文件以下分为S块,每一块描述一个咒语机,按照咒语机0,咒语机1„„咒语机S-1的顺序描述。每一块的格式如下。 一块的第一行有两个正整数n,m。分别表示该咒语机中元件的个数、咒语源输出元的个数(1≤m≤n≤50)。 接下来一行有m个数,表示m个咒语源输出元的标号(都在0到n-1之间)。接下来有n行,每一行两个数。第i行(0≤i≤n-1)的两个数表示pi,0和pi,1(当然,都在0到n-1之间)。

    Output

    第一行有一个正整数t,表示最长升级序列的长度。

    Sample Input

    4
    1 1
    0
    0 0
    2 1
    0
    1 1
    0 0
    3 1
    0
    1 1
    2 2
    0 0
    4 1
    0
    1 1
    2 2
    3 3
    0 0

    Sample Output

    3

    HINT

    Source

    Solution

    这道题还是比较有趣的..如果能够得到包含关系,可以直接拓扑排序dp求解最长链。

    然后如何判断是否包含?需要利用自动机的相关性质。

    考虑dp,$f[x][y]$表示自动机1和自动机2分别对应状态$x$和$y$,然后枚举转移更新$f[x'][y']$。

    考虑什么情况不满足包含,即$f[x][y]=1$且$end[x]=1$且$end[y]=0$表示不包含,否则一定包含。

    所以只要暴力的去枚举两两自动机跑即可,主要的思想就是去尝试构造01串使得一个能匹配另一个不能。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1; char ch=getchar();
    	while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    	while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    	return x*f;
    }
    int T,N,M;
    struct DFANode{
    	int son[55][2],end[55];
    }DFA[55],A,B;
    bool f[55][55],flag;
    
    inline void Run(int x,int y)
    {	
    	if (!x || !y || f[x][y] || !flag) return;
    	f[x][y]=1;
    	if (!A.end[x] && B.end[y]) flag=0;
    	for (int i=0; i<=1; i++)
    		Run(A.son[x][i],B.son[y][i]);
    }
    inline bool Check(DFANode x,DFANode y)
    {
    	memset(f,0,sizeof(f));
    	A=x,B=y; flag=1;
    	Run(1,1);
    	return flag;
    }
    
    struct GraphNode{
    	struct EdgeNode{
    		int next,to;
    	}edge[55*55];
    	int head[55],cnt;
    	inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    	inline void InsertEdge(int u,int v) {AddEdge(u,v);}
    }G1,G2;
    
    int visit[55],stack[55],top,dfn[55],low[55],dfsn;
    int belong[55],size[55],scc;
    inline void Tarjan(int x)
    {
    	visit[x]=1; stack[++top]=x;
    	dfn[x]=low[x]=++dfsn;
    	for (int i=G1.head[x]; i; i=G1.edge[i].next) 
    		if (!dfn[G1.edge[i].to])
    			Tarjan(G1.edge[i].to),low[x]=min(low[x],low[G1.edge[i].to]);
    		else
    			if (visit[G1.edge[i].to]) low[x]=min(dfn[G1.edge[i].to],low[x]);
    	if (dfn[x]==low[x]) {
    		int tops=0;
    		scc++;
    		while (tops!=x) {
    			tops=stack[top--];
    			belong[tops]=scc,visit[tops]=0,size[scc]++;
    		}
    	}
    }
    inline void Tarjan() {for (int i=1; i<=T; i++) if (!dfn[i]) Tarjan(i);}
    
    int mp[55][55],d[55];
    inline void Rebuild()
    {
    	for (int x=1; x<=T; x++)
    		for (int i=G1.head[x]; i; i=G1.edge[i].next)
    			if (belong[x]!=belong[G1.edge[i].to])
    				G2.InsertEdge(belong[x],belong[G1.edge[i].to]),d[belong[G1.edge[i].to]]++;
    }
    
    queue<int>q;
    int dp[55];
    inline void Toposort()
    {
    	for (int i=1; i<=scc; i++) if (!d[i]) q.push(i);
    	for (int i=1; i<=scc; i++) dp[i]=size[i];
    	while (!q.empty()) {
    		int now=q.front(); q.pop();
    		for (int i=G2.head[now]; i; i=G2.edge[i].next) {
    			dp[G2.edge[i].to]=max(dp[G2.edge[i].to],dp[now]+size[G2.edge[i].to]);
    			if (!--d[G2.edge[i].to]) q.push(G2.edge[i].to);
    		}
    	}
    }
    
    int main()
    {
    	T=read();
    	for (int i=1; i<=T; i++) {
    		N=read(),M=read();
    		for (int x,j=1; j<=M; j++)
    			x=read()+1,DFA[i].end[x]=1;
    		for (int j=1; j<=N; j++)
    			DFA[i].son[j][0]=read()+1,DFA[i].son[j][1]=read()+1;
    	}
    	for (int i=1; i<=T; i++)
    		for (int j=1; j<=T; j++)
    			if (i!=j && Check(DFA[i],DFA[j])) 
    				G1.InsertEdge(i,j);
    	Tarjan();
    	Rebuild();
    	Toposort();
    	int ans=0;
    	for (int i=1; i<=scc; i++) ans=max(ans,dp[i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    luogu P3375 【模板】KMP字符串匹配
    leetcode[129]Sum Root to Leaf Numbers
    leetcode[130]Surrounded Regions
    leetcode[131]Palindrome Partitioning
    leetcode[132]Palindrome Partitioning II
    leetcode[133]Clone Graph
    leetcode[134]Gas Station
    leetcode[135]Candy
    leetcode[136]Single Number
    leetcode[137]Single Number II
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6305872.html
Copyright © 2011-2022 走看看