AcWing 字串变换

已知有两个字串 AA, BB 及一组字串变换的规则(至多 66 个规则):

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
… …

第一行是两个给定的字符串 A 和 B。

接下来若干行,每行描述一组字串变换的规则。

所有字符串长度的上限为 20。

输出格式

若在 10 步(包含 10 步)以内能将 AA变换为 B ,则输出最少的变换步数;否则输出 NO ANSWER!

输入样例:

abcd xyz
abc xu
ud y
y yz

输出样例:

3
难度:中等
时/空限制:1s / 64MB
总通过数:5384
总尝试数:11303
来源:《算法竞赛进阶指南》
算法标签

#include<bits/stdc++.h>
using namespace std;
const int N = 6;
int n;
string A,B;
string a[N],b[N];
int extend(queue<string> &q,unordered_map<string,int> &da,unordered_map<string,int> &db,string a[],string b[])
{
	int d = da[q.front()];
	while(q.size() &&da[q.front()] == d)//确保遍历完了这一层
	{
		auto t = q.front();
		q.pop();
		
		for(int i = 0;i < n;i ++)
		{
			for(int j = 0;j < t.size();j ++)
			{
				if(t.substr(j,a[i].size()) == a[i])
				{
					string r = t.substr(0,j) + b[i] + t.substr(j + a[i].size());
					if(db.count(r))return da[t] + db[r] + 1;
					if(da.count(r))continue;
					da[r] = da[t] + 1;
					q.push(r);
				}
			}
		}
	}
	return 11;
}

int bfs()
{
	if(A == B)return 0;
	queue<string> qa,qb;
	unordered_map<string,int> da,db;
	qa.push(A),qb.push(B);
	da[A] = db[B] = 0;
	int step = 0;
	while(qa.size() && qb.size())
	{
		int t;
		if(qa.size() < qb.size()) t = extend(qa,da,db,a,b);/*
			      从节点少的队列开始拓展时间复杂度较小
                  因为节点少的队列,它拓展出来的分支也少,从而能避免枚举那些无意义的字符串
		*/
		else t = extend(qb,db,da,b,a);
		if(t <= 10)return t;
		if(++ step == 10)return -1;
	}
	return -1;
}

int main()
{
	cin >> A >> B;
	while(cin >> a[n] >> b[n])n ++;
	int t = bfs();
	if (t == -1) puts("NO ANSWER!");
	else cout << t << endl;
	return 0;
}

假设每次决策数量是 K,那么如果直接BFS,最坏情况下的搜索空间是 Ke10,非常大,所以会TLE或者MLE。

如果采用双向BFS,则可以把搜索空间降到 2Ke5。

posted @ 2022-09-24 21:16  zyc_xianyu  阅读(23)  评论(0编辑  收藏  举报