UOJ Logo zhouzixuan的博客

博客

bzoj 1194: [HNOI2006]潘多拉的盒子

2015-11-26 13:12:08 By zhouzixuan
【题目描述】:

【题目解法】:
    首先我们枚举一对自动机(i,j),然后判断j是否为i的升级
    我们可以用bfs判定,我们用(x,y)表示在i自动机的第x个节点和j自动机的第y个节点,如果到达某个状态(x,y)使得x是输出节点而y不是输出节点,那么说明存在一个字符串x可以输出y不能输出,因此j就不是i的升级,反之j就是i的升级。
    然后状态只有O(N^2),因此一次bfs复杂度就是O(N^2)
    如果j是i的升级我们连边i->j
    然后我们得到一个有向图,我们需要求出最长路
    我们先同tarjan求出SCC,对于同一个联通分量里面的点那么可以全部选取
    因此我们用拓扑dp求出最长路即可
    复杂度O(N^4)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=101;
const int M=8005;
inline long long getint()
{
    long long x=0; char c=getchar(); bool flag=false;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') flag=true,c=getchar();
    while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
    if (flag) return -x; else return x;
}
struct Auto
{
    int n,m,trans[N][2]; bool v[N];
    void init()
    {
        n=getint(); m=getint();
        for (int i=1; i<=m; i++) v[getint()+1]=true;
        for (int i=1; i<=n; i++) trans[i][0]=getint()+1,trans[i][1]=getint()+1;
    }
} a[N];
int n,size[N];
void init()
{
    n=getint();
    for (int i=1; i<=n; i++) a[i].init();
}
namespace SCC
{
    struct edge {int x,next;} b[M];
    int tot,a[N],ans,into[N],q[N],f[N];
    void addedge(int x,int y)
    {
        ++tot;
        b[tot].x=y;
        b[tot].next=a[x];
        a[x]=tot;
        into[y]++;
    }
    void solve()
    {
        int head=0,tail=0;
        for (int i=1; i<=n; i++) if (into[i]==0) q[++tail]=i,f[i]=size[i];
        while (head<tail)
        {
            int k=q[++head]; ans=max(ans,f[k]);
            for (int p=a[k];p;p=b[p].next)
            {
                int pp=b[p].x; f[pp]=max(f[pp],f[k]+size[pp]);
                --into[pp]; if (into[pp]==0) q[++tail]=pp;
            }
        }
        printf("%d\n",ans);
    }
}
namespace Tarjan
{
    struct edge {int x,next;} b[M]; int v[N];
    int tot,a[N],dfn[N],cnt,low[N],belong[N],top,stack[N],time;
    void addedge(int x,int y)
    {
        ++tot;
        b[tot].x=y;
        b[tot].next=a[x];
        a[x]=tot;
    }
    void dfs(int x)
    {
        ++time; low[x]=dfn[x]=time; stack[++top]=x; v[x]=1;
        for (int p=a[x];p;p=b[p].next)
        {
            int pp=b[p].x;
            if (v[pp]==0) dfs(pp);
            if (v[pp]==1) low[x]=min(low[x],low[pp]);
        }
        if (low[x]!=dfn[x]) return; ++cnt;
        while (stack[top+1]!=x)
        {
            v[stack[top]]=2;
            belong[stack[top]]=cnt; size[cnt]++;
            top--;
        }
    }
    void solve()
    {
        for (int i=1; i<=n; i++) if (v[i]==0) dfs(i);
        for (int i=1; i<=n; i++)
            for (int p=a[i];p;p=b[p].next)
            if (belong[i]!=belong[b[p].x]) SCC::addedge(belong[i],belong[b[p].x]);
    }
}
namespace JudgeLevel
{
    struct node {int x,y;} q[M];
    int cnt,id[N][N];
    bool bfs(int i,int j)
    {
        ++cnt; int head=0,tail=1;
        q[1].x=1; q[1].y=1; id[1][1]=cnt;
        while (head<tail)
        {
            ++head; int x=q[head].x,y=q[head].y;
            if ((a[i].v[x])&&(!a[j].v[y])) return false;
            for (int k=0; k<=1; k++)
            {
                int nx=a[i].trans[x][k],ny=a[j].trans[y][k];
                if (id[nx][ny]==cnt) continue; id[nx][ny]=cnt;
                q[++tail].x=nx; q[tail].y=ny;
            }
        }
        return true;
    }
    void solve()
    {
        for (int i=1; i<=n; i++)
            for (int j=1; j<=n; j++)
            if ((i!=j)&&(bfs(i,j))) Tarjan::addedge(i,j);
    }
}
int main()
{
    init();
    JudgeLevel::solve();
    Tarjan::solve();
    SCC::solve();
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。