洛谷P1032 字串变换

题面

给出最多6个 str1->str2 的变换规则,问能否在10次以内将给出的串1变为串2。如能,则输出最少变换次数
字符串长度不超过20

分析

从最少变换次数这里不难想到bfs,结合find查找串中是否有 str1 的可变换串,再用 string的replace方法可以直接得到变换后的串

坑点1:find只会找到一个 str1 并对其做变换,但实际上变换发生的位置可以是多个的,所以每一个节点可到达的状态不止变换规则数量那么多。
例如原串 aaab 在规则 a->c 中通过一次操作可以得到三种串:caab, acab, aacb.这些都要统计入
为了应对这种情况,用 find(string, start_pos)的方法,找到所有 str1 存在的位置即可

p = cur.find(rules[0][i], p + 1);//相当于迭代

坑点2:坑点1会带来大量可能性,不是一秒内能处理的,并且会有很多重复。
所以剪枝,策略是发现对每一个串,都要检查所有的替换规则,所以在不同位置出现的同一个串可到达的情况是相同的,于是舍弃操作次数较多才能出现的该串,只保留第一次(bfs序保证这个串操作次数要小于等于其他相同的串)。这可用hash来完成,这里用map来实现hash,发现已经出现过,则跳过。

代码

#include <stdio.h>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<map>
using namespace std;
int flag = -1;//记录答案
int num = 0;
string ans;
string rules[2][7];
queue<pair<string,int> >q;
map<string, int>m;
void bfs(string str)
{
    q.push(make_pair(str,0));
    int deep,p=0;
    string cur;
    string temp;
    while (!q.empty())
    {
        cur = q.front().first;
        deep = q.front().second;
        q.pop();
        if (cur == ans) { flag = deep;break; }
        if (m.count(cur)==1||deep == 10)continue;//m.count即hash去重
        m[cur] = 1;
        for (int i = 0; i < num; i++)
        {
            p=cur.find(rules[0][i]);
            while (p!=cur.npos)
            {
                temp = cur;
                q.push(make_pair(temp.replace(p, rules[0][i].length(), rules[1][i]), deep + 1));
                p = cur.find(rules[0][i], p + 1);//迭代寻找所有可能替换
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    string raw;
    cin >> raw >> ans;
    while (cin>>rules[0][num])
    {
        cin >> rules[1][num++];
    }
    bfs(raw);
    if (flag != -1)cout << flag;
    else cout << "NO ANSWER!";
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值