【XSY1552】自动机 构造

题目大意

  给你一个自动机,包含 n 个状态,指令集为前m个小写字母,对于每个状态 s 和每个指令i,自动机均有后继 T(s,i) 。请你求出一个长度不超过 220 的指令序列,使得无论自动机当前处在哪个状态(包括初始状态),按顺序执行指令序列的所有指令后,自动机都处于初始状态 1 。无解输出[impossible]

   1n100,1m26

题解

  首先要证明一个结论:原问题有解等价于对于任意状态 i ,都存在一个指令序列Si使得 T(s,Si)=1 T(1,Si)=1

  必要性显然。如果不存在 Si ,那么状态 i 和状态1一定不可能同时转移到状态 1

  对于充分性,我们考虑所有当前可能的状态集合U。一开始 U={1,2,3n} 。每次我们任选 U 中一个状态t,执行 St 。这样我们会得到一个集合 U ,满足 1U |U|<|U| 。这样我们经过若干步后可以得到 U={1} 。我们把所有 St 连在一起得到一个指令序列 S ,易证S是满足要求的。

  所以我们每次任选 U 中的一个状态t,求出 St ,然后执行 St ,直到 |U|=1 为止。

  对于状态 i ,求Si的时间复杂度是 O(n2) 的,执行 Si O(n3) 的,总共要执行 O(n) 次,所以时间复杂度是 O(n4) 的。

  每个 Si 的长度是 O(n2) 的,总共要执行 O(n) 次,所以答案的长度是 O(n3)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int a[110][30];
int n,m;
char s[10000010];
int cnt;
int c[110];
int d[110];
int vis[110][110];
int st[10010];
int top;
int dfs(int x,int y)
{
    if(x==1&&y==1)
        return 1;
    vis[x][y]=1;
    int i;
    for(i=1;i<=m;i++)
    {
        int lx=a[x][i];
        int ly=a[y][i];
        if(!vis[lx][ly])
        {
            st[++top]=i;
            if(dfs(lx,ly))
                return 1;
            top--;
        }
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    int i,j;
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
            a[i][j]++;
        }
    cnt=0;
    for(i=1;i<=n;i++)
        c[i]=i;
    int now=n;
    while(now>1)
    {
        memset(vis,0,sizeof vis);
        top=0;
        if(!dfs(1,c[2]))
        {
            printf("[impossible]");
            return 0;
        }
        for(i=1;i<=top;i++)
        {
            s[++cnt]=st[i]+'a'-1;
            for(j=1;j<=now;j++)
                c[j]=a[c[j]][st[i]];
        }
        sort(c+1,c+now+1);
        now=unique(c+1,c+now+1)-c-1;
    }
    s[cnt+1]='\0';
    printf("%s\n",s+1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值