主要思想:queue+map+set
说一下读入:while(cin>>x>>y),这样就行了,按ctrl+z结束输入
首先,我们很容易想到一种做法:
用队列进行宽搜(用结构体/二维数组)
map作为变换规则的储存器
set用来查重
每次在队首里找是否有能变换的部分,然后判重,入队
于是就有了以下的代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<string>
#include<set>
using namespace std;
struct node{
string s;//当前的字符串
int step;//所用的步数
};
queue<node> q;//队列
string a,b;//初始的两个串
map<string,string> m;//存规则
map<string,string>::iterator it;//要用迭代器遍历
set<string> vis;//判重
void bfs(){
while(!q.empty()){//队列不空
node z=q.front();//取出队首
q.pop();//队首出队
string x=z.s;//取元素
int y=z.step;//取元素
if(y>10){//超过10步了
cout<<"NO ANSWER!"<<endl;
return;
}
for(it=m.begin();it!=m.end();it++){//迭代器的遍历方式
string strnew=x;//如果一直用x,那么难以保证其值没有发生改变
string strx=it->first;//取<string,string>中的前一个
string stry=it->second;//取后一个
int stepnew=y;//同strnew的原因
if(((long long)strnew.find(strx))!=-1){//如果当前字符串中有这个可改变的部分
strnew.replace(strnew.find(strx),strx.size(),stry);//从这部分的起始位出发,把整个部分换成要变的部分
if(vis.find(strnew)==vis.end()){//集合中原来没有这个字符串
vis.insert(strnew);//放进去
node newpush;//准备入队
newpush.s=strnew;//赋值
newpush.step=stepnew+1;//多一步了
if(strnew==b){//已经得到答案了
cout<<stepnew+1<<endl;//直接输出
return;
}
else q.push(newpush);//入队
}
}
}
}
cout<<"NO ANSWER!"<<endl;//循环跑完了,说明找不到答案
return;
}
int main(){
cin>>a>>b;
string x,y;
while(cin>>x>>y)
m[x]=y;//保存规则
node z;
z.step=0;z.s=a;//一开始是0步
q.push(z);//初始入队
vis.insert(a);//放到集合里
bfs();//进行宽搜
return 0;
}
是不是看上去挺好的?但只有60分
下载数据,你会发现:原来一个部分可能可以有多种情况可以变化!!!
举个栗子例子:
y abc
y d
那么,由于我们采用下标方式赋值,map[y]就会与最后一个读入的值相同,即map[y]=d;
而如果用insert赋值,map[y]就会与第一个读入的值相同,即map[y]=abc
然后就······没有办法了
STL真是一项伟大的发明!
除了map,还有——multimap
它支持映射多个值,跟上面对比起来看
y abc
y d
那么y就既可以等于abc,又可以等于d
我一开始见到multimap还认为为什么有人这么傻不想要自动去重
但这时候就不支持下标赋值了,只能用insert不然不能显出其特殊之处
但在遍历时,认为map<y,abc>与map<y,d>是分开的,遍历方式是一样的
于是修改部分代码:
multimap<string,string> m;
multimap<string,string>::iterator it;
······
string x,y;
while(cin>>x>>y)
m.insert(make_pair(x,y));
(注:头文件还是map)
然而······还是WA了
继续下载数据,发现:一个字符串里可能有多个相同的部分可以变换!而如果用find函数,只能找出一个
于是——两重循环暴力走起!
暴力大法好!幸好出题人十分有良心没有出大数据
再次改动部分代码:
if(strx.size()>strnew.size())continue;//防止负数,不然莫名其妙错,我也不知道为什么(在exe里就会错)
for(int i=0;i<=strnew.size()-strx.size();i++){
string strnew=x;//上面其实已经赋过一遍值了,变量名也是一样的
string strx=it->first;//此处还是为了避免值被改掉
string stry=it->second;
int stepnew=y;
bool flag=true;//标记
for(int j=0;j<strx.size();j++)
if(strx[j]!=strnew[i+j]){//两者有不一样之处,说明不能变
flag=false;
break;
}
if(flag==false)continue;//判断条件成立就得用大括号把下面整个部分包起来,当时懒得写了
······
}
然后这道题才算完真是毒瘤啊,为什么不评个蓝题
最后给大家完整AC代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<string>
#include<set>
using namespace std;
struct node{
string s;
int step;
};
queue<node> q;
string a,b;
multimap<string,string> m;
multimap<string,string>::iterator it;
set<string> vis;
void bfs(){
while(!q.empty()){
node z=q.front();
q.pop();
string x=z.s;
int y=z.step;
if(y>10){
cout<<"NO ANSWER!"<<endl;
return;
}
for(it=m.begin();it!=m.end();it++){
string strnew=x;
string strx=it->first;
string stry=it->second;
int stepnew=y;
if(strx.size()>strnew.size())continue;
for(int i=0;i<=strnew.size()-strx.size();i++){
string strnew=x;
string strx=it->first;
string stry=it->second;
int stepnew=y;
bool flag=true;
for(int j=0;j<strx.size();j++)
if(strx[j]!=strnew[i+j]){
flag=false;
break;
}
if(flag==false)continue;
strnew.replace(i,strx.size(),stry);
if(vis.find(strnew)==vis.end()){
vis.insert(strnew);
node newpush;
newpush.s=strnew;
newpush.step=stepnew+1;
if(strnew==b){
cout<<stepnew+1<<endl;
return;
}
else q.push(newpush);
}
}
}
}
cout<<"NO ANSWER!"<<endl;
return;
}
int main(){
cin>>a>>b;
string x,y;
while(cin>>x>>y)
m.insert(make_pair(x,y));
node z;
z.step=0;z.s=a;
q.push(z);
vis.insert(a);
bfs();
return 0;
}
大部分代码都与第一份差不多,故不再重写注释,望谅解主要是打了这么多字受累了
累死我了,客官不点个赞?