刷题记录:牛客NC16742[NOIP2002]字串变换

注意:以下算法竟然在牛客上被T了一个点,但是洛谷上时可以AC的(QAQ),没想到啊,一直以为牛客数据应该是比较水的,正解的话应该是双向BFS(之后会加入这篇博客呢)

传送门:牛客

题目描述:

已知有两个字串 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。
输入:
abcd xyz
abc xu
ud y
y yz
输出:
3

emmm,这道题tm细节是真的多,为什么不上四星???

首先我们会发现这个的次数才10次,换的方案也才最多6次,显然是一道能爆搜的题目,所以我就进行爆搜

对于这道题的变换关系,学过STL的人一看是不是就想到了map,然后就快乐的使用map进行映射操作啦,然后就WA,下了一个数据之后发现这道题的映射是能一个映射多个的.这样map就挂了.但是既然决定用map了,又岂能换数组??直接搬上multimap,这个升级版的数据结构是能完成上述工作的,但是它的输入应该用[name].insert(make_pair(a,b))进行操作,至于枚举方案,和map一样可以使用迭代器也可以使用C++11的auto

对于处理完映射方面的问题之后我们就开始聊一聊具体的搜索方案.对于这道题我们采用BFS的方式进行搜索.对于刚开始给定的字符串,我们直接枚举这个字符串中有没有包含我们的映射源,假设有的话,就将其替换然后存入我的队列之中(注意,此时的替换是对于队列中的队首来说的,每一次替换都是队首,而不是前一次被替换过的),你以为这样就可以了??不不不,你可能在实现的时候没有考虑到一个字符串可能有多个可以替换的位置,或者你考虑到了,然后你觉得我已经存入了每一次换的字符诶,难道不对吗??你仔细想一下问题出在哪里呢,当时我TM卡了贼久的时间WAW所以我们还需要判断这个字符之后的各个子串

对于上述的操作我们可能需要string库中一些库函数:

比如:
find(A,B)函数,该函数一般会用到两个参数,参数A为查找字符,B参数为从哪里开始查找
replace(A,B,C)函数,用来替换字符串的某个部分,参数A为被替换字符开始替换的位置,参数B为被替换字符开始到结束的字符长度,参数C为替换字符

下面是具体的代码部分:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x = 0, w = 1;
	char ch = getchar();
	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps = 1e-8;
struct Node {
	string s;
	int deep;
};
queue<Node>q;
multimap<string, string>mp;
multimap<string, string>::iterator it;
map<string, bool>vis;
int main() {
	string A, B;
	cin >> A >> B;
	string a, b;
	while (cin >> a >> b) {
		mp.insert(make_pair(a, b));
	}
	q.push({A, 0});
	while (!q.empty()) {
		Node s = q.front();
		q.pop();
		if (s.deep > 10) {
			printf("NO ANSWER\n");
			return 0;
		}

		if (s.s == B) {
			printf("%d\n", s.deep);
			return 0;
		}
		//		for(it=mp.begin();it!=mp.end();it++) {//使用迭代器来枚举
		//			int ppos=0;
		//			while(s.s.find(it->first,ppos)!=s.s.npos) {
		//				int pos=s.s.find(it->first,ppos);
		//				string ss=s.s;
		//				ss.replace(pos,it->first.length(),it->second);
		//				if(vis[ss]==0){
		//					q.push({ss,s.deep+1});
		//					vis[ss]=1;
		//				}
		//				ppos=pos+it->first.length();
		//			}
		//		}
		for (auto it : mp) {//直接使用auto进行枚举
			int ppos = 0;
			while (s.s.find(it.first, ppos) != s.s.npos) {
				int pos = s.s.find(it.first, ppos);
				string ss = s.s;
				ss.replace(pos, it.first.length(), it.second);
				if (vis[ss] == 0) {
					q.push({ss, s.deep + 1});
					vis[ss] = 1;
				}
				ppos = pos + it.first.length();
			}
		}
	}
	printf("NO ANSWER!\n");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值