[POJ 3599] Pumping Lemma [BFS]

20 篇文章 0 订阅
17 篇文章 0 订阅

给定一个自动机,最多1000个节点,问能否存在一个字符串xyz,其中x,y,z均为一个字符串,且y的长度不为空,使得xz,xyz,xyyz,xyyyz,...均能被自动机识别。

有这样的字符串的条件是,存在一个节点i,从初始态出发,到达节点i,构成了字符串x,从i出发,到达一个结束态,构成了字符串z,从i出发,走不小于一条边,回到i,构成字符串y。

所以做法是,先bfs一遍,看哪些点可以从初始态到达。再在反向图上bfs一遍,看哪些点可以到达结束态。再从每个从初始态能到的且能到结束态的点上bfs一遍,看能否回到自己。如果能,则已经找到一组答案。如果不存在这样的节点,则找不到。

最开始读错题了..当成只需要xyz,xyyz,...能被识别就可以了...于是写麻烦了好多...

#include <cstdio>
#include <cstring>
#include <string>

using namespace std;

struct Edge {
	int t;
	char c;
	Edge *ne;
	void clear(int tt,char cc,Edge *&nee) {
		t=tt;c=cc;ne=nee;
		nee=this;
	}
};

string startx[1001];
string endz[1001];
bool st[1001]={0};
bool fin[1001]={0};
Edge b[52000],*bp;
Edge *fe[1001]={0};
Edge *rfe[1001]={0};
int from[1001];
char cf[1001];
int que[1001];
int n,s,p,q;
char str[1001];

void bfs(Edge **fe,bool opt=true) {
	int i;
	for (i=0;i<=n;i++) from[i]=-1;
	if (opt) for (i=p;i<q;i++) from[que[i]]=-2;
	while (p!=q) {
		i=que[p++];
		for (Edge *j=fe[i];j;j=j->ne) {
			int t=j->t;
			if (from[t]==-1) {
				from[t]=i;
				cf[t]=j->c;
				que[q++]=t;
			}
		}
	}
}
string getS(int j,bool opt=true) {
	int ss=0;
	while (from[j]!=-2) {
		str[ss++]=cf[j];
		j=from[j];
	}
	if (opt) {
		for (int i=0;i+i<ss;i++) {
			char c=str[i];
			str[i]=str[ss-i-1];
			str[ss-i-1]=c;
		}
	}
	str[ss]='\0';
	return string(str);
}
string getY(int j) {
	int ss=0,f=j;
	do {
		str[ss++]=cf[j];
		j=from[j];
	} while (j!=f);
	for (int i=0;i+i<ss;i++) {
		char c=str[i];
		str[i]=str[ss-i-1];
		str[ss-i-1]=c;
	}
	str[ss]='\0';
	return string(str);
}
bool canFindAns() {
	for (int i=0;i<=n;i++) {
		if (st[i]&&fin[i]) {
			p=q=0;
			que[q++]=i;
			bfs(fe,false);
			if (from[i]!=-1) {
				printf("%s(%s)%s\n",startx[i].c_str(),getY(i).c_str(),endz[i].c_str());
				return true;
			}
		}
	}
	return false;
}
void calEndZ() {
	p=q=0;
	for (int i=0;i<=n;i++)
		if (fin[i]) que[q++]=i;
	bfs(rfe);
	for (int i=0;i<=n;i++) {
		if (from[i]!=-1) {
			fin[i]=true;
			endz[i]=getS(i,false);
		}
	}
}
void calStartX() {
	p=q=0;
	que[q++]=s;
	bfs(fe);
	for (int i=0;i<=n;i++) {
		if (from[i]!=-1) {
			st[i]=true;
			startx[i]=getS(i);
		} 
	}
}

int main() {
	int i,m,k;
	scanf("%d%d",&n,&s);
	scanf("%d",&m);
	bp=b;
	for (i=0;i<m;i++) {
		int x,y;
		char c;
		scanf("%d %c%d",&x,&c,&y);
		(bp++)->clear(y,c,fe[x]);
		(bp++)->clear(x,c,rfe[y]);
	}
	scanf("%d",&k);
	for (i=0;i<k;i++) {
		int x;
		scanf("%d",&x);
		fin[x]=true;
	}
	st[s]=true;
	calStartX();
	calEndZ();
	if (!canFindAns()) printf("*\n");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值