首页 > 代码库 > NOIP2002 字串变换题解(双向搜索)

NOIP2002 字串变换题解(双向搜索)

65. [NOIP2002] 字串变换


时间限制:1 s   内存限制:128 MB

[问题描述]

已知有两个字串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!"

[输入样例]

abcd xyz
abc xu
ud y
y yz

[输出样例]

3
  在这里膜拜一下wq大佬,强行bfs藐视数据,我就比较惨了,打了好几次,正着搜反着搜都会T某个点,这就比较尴尬了,于是乎,我们引进了双向搜索这个概念。
  我们可以把宽搜想像为一棵树,为了方便计算,我们暂定它为二叉树好了,如果我要搜10层,我单项搜索,会有2047个节点,但如果我双向搜索,就只有63+63==126个节点了,由此可见,双向可以说是完爆单向的,何况这只是二叉树。
  于是这道题在双向搜索的前提下就无比简单了,我们把A,B分别塞进两个队列,同时广搜,直到两者相遇。至于修改操作吗,string就可以搞定了。
  
技术分享
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<map>
  7 #include<queue>
  8 #include<string>
  9 #include<cmath>
 10 using namespace std;
 11 string a,b;
 12 string A[10],B[10];
 13 struct st{
 14     string x;
 15     int js;
 16 };
 17 int js;
 18 queue<st> q1;
 19 bool yx;
 20 int p=12345,q=10000007;
 21 unsigned long long xp[50];
 22 int fw[2][10000007];
 23 bool get_hash(st x,int be){
 24     unsigned long long has=0;
 25     for(int i=x.x.length()-1;i>=0;i--)
 26     {
 27         has=has*p+int(x.x[i]);
 28     }
 29     has%=q;
 30     if(fw[be][has])
 31         return 1;
 32     fw[be][has]=x.js;
 33     if(fw[be^1][has])
 34     {
 35         printf("%d\n",x.js+fw[be^1][has]);
 36         exit(0);
 37     }
 38         return 0;
 39 }
 40 queue<st> q2;
 41 void bfs(){
 42     while(!q1.empty()&&!q2.empty())
 43     {
 44         st aa=q1.front();
 45         q1.pop();
 46         if(aa.js>6)
 47         {
 48             yx=1;
 49             printf("NO ANSWER!\n");
 50             return;
 51         }
 52         for(int i=1;i<=js;i++)
 53         {
 54             int la=-1;
 55             for(int j=0;j<=aa.x.length();j++)
 56             {
 57                 long long t=aa.x.find(A[i],j);
 58                 if(t>=0&&t<=20&&t!=la)
 59                 {
 60                     la=t;
 61                     j=la-1;
 62                     st c;
 63                     c.x=aa.x;
 64                     c.x.replace(t,A[i].length(),B[i]);
 65                     c.js=aa.js+1;
 66                     if(c.x.length()<=20&&!get_hash(c,0)&&c.js<=10)
 67                     {
 68                         q1.push(c);
 69                     }
 70                 }
 71             }   
 72         }
 73         st bb=q2.front();
 74         q2.pop();
 75         if(bb.js>6)
 76         {
 77             yx=1;
 78             printf("NO ANSWER!\n");
 79             return;
 80         }
 81         for(int i=1;i<=js;i++)
 82         {
 83             int la=-1;
 84             for(int j=0;j<=bb.x.length();j++)
 85             {
 86                 long long t=bb.x.find(B[i],j);
 87                 if(t>=0&&t<=20&&t!=la)
 88                 {
 89                     la=t;
 90                     j=la-1;
 91                     st c;
 92                     c.x=bb.x;
 93                     c.x.replace(t,B[i].length(),A[i]);
 94                     c.js=bb.js+1;
 95                     if(c.x.length()<=20&&!get_hash(c,1)&&c.js<=10)
 96                     {
 97                         q2.push(c);
 98                     }
 99                 }
100             }   
101         }
102     }
103 }
104 int main(){
105     cin>>a>>b;
106     js=1;
107     while(cin>>A[js]>>B[js])
108     {
109         js++;
110     }
111     js--;
112     st xx;
113     xx.x=a;
114     xx.js=0;
115     q1.push(xx);
116     get_hash(xx,0);
117     st yy;
118     yy.x=b;
119     yy.js=0;
120     q2.push(yy);
121     get_hash(yy,1);
122     xp[0]=1;
123     for(int i=1;i<=20;i++)
124     {
125         xp[i]=xp[i-1]*p;
126     }
127     bfs();
128     if(!yx)
129         printf("NO ANSWER!\n");
130     //while(1);
131     return 0;
132 }
View Code

 

NOIP2002 字串变换题解(双向搜索)