字串变换 (2002 年NOIP全国联赛提高组)

          一道看似非常水的题

  大意 :将一个字串 经过几种变换规则变为给定的另一个子串 ,求最小操作数。

 

  code[vs] 传送门

  洛谷传送门

 

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

  

  思路:从前从后双向BFS 不加限制 若递归次数等于10次仍未找到答案时,输出NO ANSWER 。其他的若替换完后 从 前端BFS的串 在从后端BFS出现过,则此时递归次数乘2减一即为答案,   从后端BFS的情况同上。   具体实现,就按照题意来,依次扫描变换规则,进行替换,替换完的字串加入队列。

  双向BFS

#include <iostream>
#include <cstring>
#include <map>
#include <cstdio>
using namespace std;
const int Max = 1000000;
string A, B;
string s_change [7][2], Front[Max], Back[Max];
int Limit = 1, head_Front = 1, tail_Front = 1, tail_Back = 1, head_Back = 1, tot = 0;
map < string , int > Map_Front;
map < string , int > Map_Back;
void BFS ()
{
    tot++;  //记录递归次数 
    string s, s_replace;  // s是  变换后的字串 ,s_replace 是当前需变换的字串 
    int head, tail;
    head = head_Front; //调整指针 
    tail = tail_Front; 
    for (int i = head; i <= tail; i++)
        for (int j = 1; j <= Limit; j++)  //变换种数 ,变为不同的替换规则 
        {
            int change_Front = 0;   
            while (change_Front != -1)   //每个字串中可以替换的字串不止一个 
            {
                s_replace = Front [i];  //取出当前需被变换的字串 
                change_Front = s_replace.find (s_change [j][0], change_Front );   //查找变换规则 ,change_Front是 当前规则 出现的位置 
                if (change_Front >= 0) 
                {
                    s = s_replace.replace (change_Front, s_change [j][0].length(), s_change [j][1]);  //进行替换, s存的是替换完的字串 
                    if (Map_Front [s] == 0)  //剪枝 ,若该字串出现过,则不进入队列 
                    {
                        if (Map_Back [s] != 0)    //如果能在中间遇到,就直接输出答案     
                        {
                            cout << tot * 2 - 1;
                            return ;
                        }
                        Front [++tail_Front] = s;  //加入队列 
                        Map_Front [s] = 1;    //标记为出现过 
                    }
                }
                if (change_Front != -1) change_Front += s_change[j][1].length();   //寻找下一个字串 
            }
        }
    head_Front = tail + 1;        //同上 ,不过是从后面进行BFS 
     head = head_Back;
    tail = tail_Back;
    for (int i = head; i <= tail; ++i)
        for (int j = 1; j <= Limit; ++j)
        {
            int change_Back = 0;
            while (change_Back != -1)
            {
                s_replace = Back[i];
                change_Back = s_replace.find (s_change[j][1], change_Back);
                if (change_Back >= 0)
                {
                    s = s_replace.replace (change_Back, s_change [j][1].length(), s_change[j][0]);
                    if (Map_Back[s] == 0)
                    {
                        if(Map_Front[s] != 0)
                        {
                            cout << tot * 2;
                            return ;
                        }
                        Back[++tail_Back] = s;
                        Map_Back[s] = 1;
                    }
                } 
                if (change_Back != -1) change_Back = change_Back + s_change [j][0].length();
            }
        }
    head_Back = tail + 1;
    if (tot == 10)    //以十次为限,若十次后仍未找到,则输出NO ANSWER 
    {
        cout << "NO ANSWER!";
        return;
    }
    BFS (); 
}
int main()
{
    ios::sync_with_stdio (false);
    cin >> A >> B; 
    while (cin >> s_change[Limit][0] >> s_change [Limit][1]) Limit++;   
    Limit--;  // 替换的组数 
    Map_Front [A] = 1;  //用 map 记录 
    Map_Back [B] = 1;
    Front [1] = A;  //加入队列 
    Back [1] = B;  
    BFS ();
    return 0;
}

 

  注意:此题属于那种看似很水,但是实现有难度的题。。

posted @ 2016-11-08 15:32  ZlycerQan  阅读(1046)  评论(0编辑  收藏  举报