题目链接:POJ 3087
题意:
有两副牌s1和s2各c张,每张纸牌用一个字符表示纸牌的颜色。还有一副2*c张的纸牌s。
先抽取s2的最底下一张纸牌(第c张),然后抽取s1最底下的一张纸牌(第c张)叠放在其上面,再抽取s2的最底下一张纸牌(此时是初始时的第c-1张)叠放在上面,接着然后抽取s1最底下的一张纸牌(此时也是初始时的第c-1张)叠放在其上面.....最后会形成一副2*c的纸牌,如果这个纸牌的颜色顺序和s不一致,那么抽取下层的c张作为新的s1,上层的c张作为新的s2,重复操作。问能否通过若干次洗牌使得洗出来的纸牌和s颜色顺序一致,若能,输出洗牌次数,否则输出-1.
思路:
判断-1退出的方法有两种。
- 将之前的所有洗牌序列记录下来,一旦新出现的游戏牌序列和之前的有重复那么就可以退出了。记录的方式可以用,map映射,链表,set集合。
- 新拆分出的s1和s2与输入相同,这时也需要退出。这种方法需要一开始就先把s1和s2“复制”保留下来,然后用字符串模拟操作。
下面提供几种解法,一起学习~
/*
*********BFS************
*/
#include <iostream>
#include <map>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
int n, len, cases;
string s1, s2, s, t;
map<string, int> mp;
//映射mp[t]=num,表示得到洗牌序列t需要洗牌num次
void Shuffle()
{//洗牌
t = "";
for (int i = 0;i < len;i++)
{
t += s2[i];
t += s1[i];
}
}
int BFS()
{
mp.clear();//每种样例输入需要清空mp
queue<string> q;
Shuffle();
mp[t] = 1;
q.push(t);
while (!q.empty())
{
string front = q.front();
q.pop();
if (front == s) return mp[front];
s1 = front.substr(0, len);//拆分s1和s2
s2 = front.substr(len, len);
Shuffle();
if (mp[t] > 0) return -1;//所洗出来的牌之前已经洗出来过了
mp[t] = mp[front] + 1;//得到纸牌序列t的洗牌次数是mp[front] + 1
q.push(t);
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
cin >> n;
for (cases = 1;cases <= n;cases++)
{
cin >> len >> s1 >> s2 >> s;
int ans = BFS();
cout << cases << " " << ans << endl;
}
return 0;
}
/*
**********链表***********
*/
#include <iostream>
using namespace std;
char s1[100], s2[100], skey[210], stemp[210];
int n, len, cases, cnt;
struct Node {
char s[210];
struct Node* next;
}*head, *newnode, *tmp, *tail;
void Shuffle()
{
for (int i = 0;i < len;i++)
{
stemp[2 * i] = s2[i];
stemp[2 * i + 1] = s1[i];
}
stemp[2 * len] = '\0';
}
int Judge()
{
head = (Node*)malloc(sizeof(Node));
head->next = NULL;
tail = head;
cnt = 0;
while (1)
{
Shuffle();
cnt++;
if (strcmp(stemp, skey) == 0) return cnt;
tmp = head;
while (tmp->next != NULL)
{
if (strcmp(tmp->s, stemp) == 0) return -1;所洗出来的牌之前已经洗出来过了
tmp = tmp->next;
}
newnode = (Node*)malloc(sizeof(Node));//尾插新结点
strcpy(newnode->s, stemp);
newnode->next = NULL;
tail->next = newnode;
tail = newnode;
for (int i = 0;i < len;i++)
{//拆分出s1,s2
s1[i] = stemp[i];
s2[i] = stemp[i + len];
}
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
cin >> n;
for (cases = 1;cases <= n;cases++)
{
cin >> len >> s1 >> s2 >> skey;
int ans = Judge();
cout << cases << " " << ans << endl;
}
return 0;
}
/*
************集合set*************
*/
#include <iostream>
#include <string>
#include <set>
using namespace std;
string s1, s2, s, T;
int n, len, cnt, cases;
set<string> myset;
void Shuffle()
{
T = "";
for (int i = 0;i <len;i++)
{
T += s2[i];
T += s1[i];
}
}
int Judge()
{
myset.clear();
cnt = 0;
while (1)
{
Shuffle();
cnt++;
if (s == T) return cnt;
if (myset.count(T) == 1) return -1;
else
{
s1.assign(T, 0, len);
s2.assign(T, len, len);
myset.insert(T);
}
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w",stdout);
#endif
scanf("%d", &n);
for (cases = 1;cases <= n;cases++)
{
cin >> len >> s1 >> s2 >> s;
int ans = Judge();
printf("%d %d\n", cases, ans);
}
return 0;
}
/*
***********string类字符串模拟*********
*/
#include <iostream>
#include <string>
#include <set>
using namespace std;
int n, cnt, len, cases;
string s1, s2, s, T1, T2, T;
void Shuffle()
{
s = "";
for (int i = 0;i < len;i++)
{
s += s2[i];
s += s1[i];
}
s1 = "";
s2 = "";
}
int Judge()
{
cnt = 0;
T1 = s1;
T2 = s2;
while (1)
{
Shuffle();
cnt++;
if (s.compare(T)==0) return cnt;
for (int i = 0;i < len;i++)
{
s1+= s[i];
s2+= s[i + len];
}
s1[len] = s2[len] = '\0';
if (s1.compare(T1) == 0 && s2.compare(T2)==0) return -1;
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d", &n);
for (cases = 1;cases <= n;cases++)
{
cin >> len >> s1 >> s2 >> T;
int ans = Judge();
printf("%d %d\n", cases, ans);
}
return 0;
}