题意
输入一个N,表示有N组数据,每组数据有四行,第一行是一个整数C,表示 每堆牌的数量,接下来是三行字符序列,第一行是S1堆,第二行是S2堆,第三行S12是预想的排序序列,求需要几步才能到达预想序列。
已知两堆牌s1和s2的初始状态, 其牌数均为c,按给定规则能将他们相互交叉组合成一堆牌s12,再将s12的最底下的c块牌归为s1,最顶的c块牌归为s2,依此循环下去。现在输入s1和s2的初始状态 以及 预想的最终状态s12.问s1 s2经过多少次洗牌之后,最终能达到状态s12,若永远不可能相同,则输出"-1"。
分析
洗牌。两摞牌数相同。每个字母代表一个颜色,给出两摞牌的顺序,最后一行为洗牌目标。
利用bfs搜索。每摞最后一个为s2的,最上面的是s1的,如果新的序列s与目标序列相同,返回洗牌次数,如果不相同,将序列s重新分成两摞,下半部分是s1的,上半部分是s2的。由此进行。
每次洗牌需进行查重。防止进入循环状态而无解。
#include<iostream>
#include<queue>
#include<cstdio>
#include<map>
using namespace std;
int n,m,t;
string s1,s2,s;
struct node{
int num;//计数
string s;
};
map<string,int>p;
int bfs(node a)
{
queue<node>q;
p.clear(); //删除所有元素
q.push(a);//从已有元素后增加元素
while(!q.empty()){//判断是否为空
node u=q.front();//把第一个元素给u
q.pop();//清除第一个元素
if(u.s==s&&u.num!=0)
return u.num;
node v;
int i;
for(i=0;i<n;i++)//洗牌穿插
{
v.s += u.s[n+i];
v.s +=u.s[i];
}
if(!p.count(v.s)){//判断是否为目标顺序
p[v.s]=1;//标记。证明其不会有重复的顺序
v.num=u.num+1;
q.push(v);
}
}
return -1;
}
int main()
{
int k=0;
cin>>t;
while(t--)
{
cin>>n>>s1>>s2>>s;
node u;
u.s=s1+s2;
u.num=0;
int ans=bfs(u);
printf("%d %d\n",++k,ans);
}
}