题目大意:
已知两堆牌
s1
和
s2
的初始状态,
其牌数均为
c
,按给定规则能将他们相互交叉组合成一堆牌
s12
,再将
s12
的最底下的
c
块牌归为
s1
,最顶的
c
块牌归为
s2
,依此循环下去。
现在输入s1和s2的初始状态 以及 预想的最终状态s12
问s1 s2经过多少次洗牌之后,最终能达到状态s12,若永远不可能相同,则输出"-1"。
题目链接:点击打开链接
分析:网上将这题放在了BFS里,可这里的变换是固定的,所以实在是想不出怎么BFS,,,由于每次操作都是给定的,所以就是个简单的模拟题。这里要注意到的一点就是判重(即永远也不能变成需要的牌堆),用map就可以轻松解决了。值得一提的是,如何正确使用map。请看代码注释。
附上代码:
#include<iostream> //POJ-3087
#include<string>
#include<map>
using namespace std;
int N, n;
string s1, s2, s, ss;
map<string, int> vis;
int solve()
{
int res = 0;
while (1)
{
for (int i = 0; i < n; i++) //s1+s2->s,合并
{
s[2 * i] = s2[i];
s[2 * i + 1] = s1[i];
}
res++;
if (s == ss) return res; //如果达到就返回res
if (vis[s]) return -1; //在这里,可能刚接触STL的人就看不太懂了,在前面我们并没有执行vis[s]=1;将s这个键加入到vis中之类的
vis[s] = 1; //操作。这就是前面说到值得注意的一点,vis[s]这个操作会自动将s这个键加入,并将对应的键值默认为0。
for (int i = 0; i < n; i++) //s->s1+s2,拆分
{
s1[i] = s[i];
s2[i] = s[i + n];
}
}
}
int main()
{
scanf("%d", &N);
int T = 0;
while (T++ < N)
{
scanf("%d", &n);
cin >> s1 >> s2 >> ss;
s.resize(2 * n); //重定义s的大小,以便于在之后可以直接用取下标的方式赋值
printf("%d %d\n", T, solve());
}
return 0;
}