洛谷 P1032 [NOIP 2002 提高组] 字串变换
【题目链接】
洛谷 P1032 [NOIP 2002 提高组] 字串变换
【题目考点】
1. 广搜
2. 双向广搜
【解题思路】
解空间树中每个结点包含的状态为一个字符串s,该结点的子结点中的字符串为字符串s通过变换规则可以变化而成的字符串。求从起始字符串变换为最终字符串的最少变换步数,需要使用广搜算法。
队列中保存的元素为字符串以及起始字符串变成该字符串的变化步数。
首先将起始字符串入队,每次循环出队一个字符串u,对于每个
a
i
→
b
i
a_i\rightarrow b_i
ai→bi的变换规则,已知字符串
a
i
a_i
ai的长度为len,枚举字符串u中所有长为len的子串,如果存在子串为
a
i
a_i
ai,则生成将u中该子串
a
i
a_i
ai替换为
b
i
b_i
bi后的字符串t,判断t是否已出现过,如果t未出现过,则标记t已出现过,而后将t加入队列,变化的步数要增加1。(可以使用map或set来标记以及查询一个字符串是否已经出现过。)。
如果出队的字符串u是目标字符串,且步数小于等于10步,则返回变化步数。如果步数大于10步,则不再扩展子结点入队。
本问题也可以使用双向广搜完成,起点和终点字符串同时入队,记录从起点还是从终点出发访问某字符串。如果一个字符串经过变换后得到的字符串是已经能从另一个源头出发变换得到,那么就找到了一条从起点到终点的路径,返回路径长度。
【题解代码】
解法1:广搜
# include<bits/stdc++.h>
using namespace std;
#define N 25
struct Node
{
string s;
int d;
};
string st, ed, a[N], b[N];
int n;
map<string, bool> vis;
int bfs()
{
queue<Node> que;
vis[st] = true;
que.push(Node{st, 0});
while(!que.empty())
{
string u = que.front().s;
int d = que.front().d;
que.pop();
if(d > 10)//超过10步,没有结果
return -1;
if(u == ed)
return d;
for(int i = 0; i < n; ++i)//看a[i]->b[i]
{
int len = a[i].length();
for(int j = 0; j+len <= u.length(); ++j) if(u.substr(j, len) == a[i])
{
string t = u;
t.replace(j, len, b[i]);
if(!vis[t])
{
vis[t] = true;
que.push(Node{t, d+1});
}
}
}
}
return -1;
}
int main()
{
cin >> st >> ed;
while(cin >> a[n] >> b[n])//下标从0~n-1
n++;
int ans = bfs();
if(ans == -1)
cout << "NO ANSWER!";
else
cout << ans;
return 0;
}
2. 双向广搜
#include<bits/stdc++.h>
using namespace std;
string x, y, a[10], b[10];
int n;
map<string, int> vis, dis;
int bfs()
{
queue<string> que;
vis[x] = 1, vis[y] = 2;
dis[x] = 0, dis[y] = 0;
que.push(x);
que.push(y);
while(!que.empty())
{
string u = que.front();
que.pop();
for(int i = 0; i < n; ++i)
{
int len = a[i].length();
for(int j = 0; j+len <= u.length(); ++j) if(u.substr(j, len) == a[i])
{
string t = u;
t.replace(j, len, b[i]);
if(vis[t] == 0)
{
vis[t] = vis[u];
dis[t] = dis[u]+1;
if(dis[t] <= 10)
que.push(t);
}
else if(vis[t] != vis[u])
{
if(dis[t]+dis[u]+1 <= 10)
return dis[t]+dis[u]+1;
}
}
}
}
return -1;
}
int main()
{
cin >> x >> y;
while(cin >> a[n] >> b[n])
n++;
int ans = bfs();
if(ans == -1)
cout << "NO ANSWER!";
else
cout << ans;
return 0;
}