【XSY1552】自动机 构造

题目大意

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

  \(1\leq n\leq 100,1\leq m\leq 26\)

题解

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

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

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

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

  对于状态\(i\),求\(S_i\)的时间复杂度是\(O(n^2)\)的,执行\(S_i\)\(O(n^3)\)的,总共要执行\(O(n)\)次,所以时间复杂度是\(O(n^4)\)的。

  每个\(S_i\)的长度是\(O(n^2)\)的,总共要执行\(O(n)\)次,所以答案的长度是\(O(n^3)\)

代码

#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;
}
posted @ 2018-03-05 18:54  ywwyww  阅读(166)  评论(0编辑  收藏  举报