noip2002 字串变换 (双向宽搜,交替扩展)

P1124字串变换

描述

已知有两个字串 A$, B$ 及一组字串变换的规则(至多6个规则):
A1$ -> B1$
A2$ -> B2$
规则的含义为:在 A$中的子串 A1$ 可以变换为 B1$、A2$ 可以变换为 B2$ …。

例如:A$='abcd' B$='xyz'
变换规则为:
‘abc’->‘xu’ ‘ud’->‘y’ ‘y’->‘yz’
则此时,A$ 可以经过一系列的变换变为 B$,其变换的过程为:
‘abcd’->‘xud’->‘xy’->‘xyz’
共进行了三次变换,使得 A$ 变换为B$。

格式

输入格式

第一行为两个字符串,第二行至文件尾为变换规则
A$ B$
A1$ B1$ \
A2$ B2$ |-> 变换规则
... ... / 
所有字符串长度的上限为 20。

输出格式

若在 10 步(包含 10步)以内能将 A$ 变换为 B$ ,则输出最少的变换步数;否则输出"NO ANSWER!"

样例1

样例输入1[复制]

abcd xyz
abc xu
ud y
y yz

样例输出1[复制]

3

限制

每个测试点1s

来源

noip2002提高组第二题


解析:设从正向开始扩展的状态储存在q数组,[l1,l2]为当前正向扩展出的状态,p数组以及l2,r2的定义类似。

           正向每扩展出一个状态,就在[l2,r2]中暴力查找是否存在相同的状态,若有,则得到答案。

           逆向扩展与正向扩展类似。

          我这里采用的是交替扩展,即正向扩展一次,然后逆向扩展一次。当然,也可以每次选择状态数更少的那个进行扩展,实际上这种方法更好。

代码:

#include<cstdio>
#include<cstring>
#define maxn 100000 
#define max_len 50
using namespace std;

char q[maxn+10][max_len+10];
char p[maxn+10][max_len+10];
char x[10][max_len],y[10][max_len];
int n=0,add[10],xl[10],yl[10];

int main()
{
  int i,j,k,xx,step,len;
  char jiewei;
  
  scanf("%s%s",q[0],p[0]);
  jiewei=p[0][strlen(p[0])];
  while(scanf("%s%s",x[n],y[n])==2)
    {
      xl[n]=strlen(x[n]),yl[n]=strlen(y[n]);
      add[n]=yl[n]-xl[n];
	  n++;
	}
  
  if(n==0)
    {
      if(strcmp(q[0],p[0])==0)printf("0\n");
      else printf("NO ANSWER!\n");
	  return 0;  
    }
  
  int l1=0,r1=0,s1=0;
  int l2=0,r2=0,s2=0;
  for(step=1;step<=5;step++)
    {
      for(i=0;i<n;i++)
	    for(j=l1;j<=r1;j++)
	      for(len=strlen(q[j]),k=0;k<len && len+add[i]<max_len;k++)
	        if(strncmp(x[i],q[j]+k,xl[i])==0)
	          {
	            s1++;
	            strncpy(q[s1],q[j],k);
	            strncpy(q[s1]+k,y[i],yl[i]);
	            strncpy(q[s1]+k+yl[i],q[j]+k+xl[i],len-k-xl[i]);
	            q[s1][len+add[i]]=jiewei;
	            
	            for(xx=l2;xx<=r2;xx++)
	              if(strcmp(p[xx],q[s1])==0)
	                {
	                  printf("%d\n",step+step-1);
	                  return 0;
	                }
	          }
	  if(s1!=r1)l1=r1+1,r1=s1;        
	          
      for(i=0;i<n;i++)
	    for(j=l2;j<=r2;j++)
	      for(len=strlen(p[j]),k=0;k<len && len-add[i]<max_len;k++)
	        if(strncmp(y[i],p[j]+k,yl[i])==0)
	          {
	            s2++;
	            strncpy(p[s2],p[j],k);
	            strncpy(p[s2]+k,x[i],xl[i]);
	            strncpy(p[s2]+k+xl[i],p[j]+k+yl[i],len-k-yl[i]);
	            p[s2][len-add[i]]=jiewei;
	            
	            for(xx=l1;xx<=r1;xx++)
	              if(strcmp(q[xx],p[s2])==0)
	                {
	                  printf("%d\n",step+step);
	                  return 0;
	                }
	          }
	  if(s2!=r2)l2=r2+1,r2=s2;		  		    
    }  
  printf("NO ANSWER!\n");    
  return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值