【p1032-子串变换】解题记录

来源:互联网 发布:手机淘宝会员怎么注册 编辑:程序博客网 时间:2024/06/04 20:10

原题点 这里

这是一道经典的搜索问题,但是数据比较弱,直接用宽度优先搜索就能通过。

简单地说,思路就是:

  1. 把原字符串入队,并设该元素之前的变换次数为 0 。
  2. 取出队首元素,如果队列为空,则没有答案,结束程序。
  3. 如果该元素等于目标字符串,输出它的变换次数,结束程序。
  4. 检查该元素之前是否出现过,如果是则不必重复搜索,返回第 2 步。
  5. 检查该元素之前的变换次数是否达到 10 。是则不能再变换返回第 2 步。
  6. 枚举它所有的变换结果,令其变换次数增加 1,然后入队。
  7. 回到第 2 步。

用伪代码描述一下的话,就是:

read(origin: 原字符串, target: 目标字符串, rule: 变换规则);var queue: 空队列, visited: 空集合;queue.push({origin, 0}); // { 字符串, 变换次数 }while(queue 不空){    var {str, cnt} = queue.front();    queue.pop_front();    if(str==target){ print(cnt); exit(0); }    if(str in visited or cnt>=10) continue;    visited.insert(str);    for(t = str 按照 rule 变换的每一个结果){        queue.push_back({t, cnt+1});    }} print("NO ANSWER!"); exit(0);

C++ 代码如下:

#include <iostream>#include <string>#include <vector>#include <set>#include <queue>#include <cstdlib>using namespace std;struct Unit{    string s;    int cnt;};typedef vector<pair<string,string> >::iterator Iter;string origin, target;vector<pair<string,string> > rule;set<string> visited;queue<Unit> q;void bfs(){    q.push((Unit){origin, 0});    while(!q.empty()){        Unit front= q.front(); q.pop();        const string &s= front.s;        const int cnt=front.cnt;        if(s==target){            cout<<cnt<<'\n';            exit(0);        }        if(cnt>=10||visited.find(s)!=visited.end()) continue;        visited.insert(s);        for(Iter beg= rule.begin(), end= rule.end(); beg!=end; ++beg){            string &key= beg->first, &val= beg->second;            for(int i=s.find(key, 0); i!=string::npos; i= s.find(key, i+1)){                string tmp= s;                q.push((Unit){tmp.replace(i, key.size(), val), cnt+1});            }        }    }    cout<<"NO ANSWER!\n";    exit(0);}int main(){    ios::sync_with_stdio(false);    cin.tie(0);    cin>>origin>>target;    string key,val;    while(cin>>key>>val){        rule.push_back(make_pair(key, val));    }    bfs();    return 0;}

实际上,该题还可以用 DFS+剪枝,或者双向 BFS 解决,可达到更高的性能。这里就不贴代码了。

0 0
原创粉丝点击