POJ - 3087 Shuffle‘m Up (kuangbin - 简单搜索)

题目描述(已转换成中文)

  还记得2020年招新赛中“编织字符串”这一道题吗?
  tls在ac完以后想出了一个更有趣的问题,具体是这样的:给定两个长度均为len的字符串s1、s2和一个长度为len2的字符串s,每一次我们按照编织字符串的操作将s1和s2拼接起来(注意这里s2先拼接,具体请看样例),得到长度为len2的字符串s’,然后令s1为s’的前一半,s2为s’的后一半,反复以上操作。若在某一次中s’和s相等则结束循环。
  假设有s1=“JNU”,s2=“ACM”,s=“NAMJUC”,第一次操作后得到s’=“AJCNMU”,与s不相等。令s1=“AJC”,s2=“NMU”,第二次操作后得到s’=“NAMJUC”,与s相等,结束循环。输出操作次数为2。

输入格式

  第一行一个整数T(1≤T≤1000),代表测试数据组个数。
  对于每组数据,第一行为len(1≤len≤100),第二行为字符串s1,第三行为字符串s2,第四行为字符串s。
  输入保证s1和s2长度均为len,s长度为len*2

输出格式

  对每一组数据,输出数据组编号和答案。如果无论经过多少次操作也无法结束循环,答案输出-1。

输入输出样例
输入

2
3
JNU
ACM
NAMJUC
3
JNU
ACM
ACMJNU

输出

1 2
2 -1

题目链接

分析:

  这道题是对字符串进行处理,问能不能得到目标字符串,并输出得到目标字符串所需的操作次数。不断循环分割字符串,再拼接,如果遇到字符串(不是目标字符串的)是之前出现过的,则之后会陷入循环,永远得不到目标字符串,输出-1.

这道题需要注意的地方:

  要用map <string, int> q来记录某个字符串是否之前出现过,q[s] == 1即代表字符串s之前出现过一次,这种关联函数很好用。

代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
using namespace std;
typedef long long LL;
char a[105], b[105], c[210], s[210];
int read(){
	int x, f = 1;
	char ch;
	while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
	x = ch - '0';
	while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
	return x * f;
}
int main(){
	int i, j, ans, sum, l, p, t = read();
	for(j = 1; j <= t; j++){
		p = 0;	//标记在得到目标字符串的过程中,某个字符串是否出现过两次
		ans = 0;	//标记操作的次数
		l = read();
		scanf("%s", a);	//输入s1
		scanf("%s", b);	//输入s2
		scanf("%s", c);	//输入目标字符串
		map<string, int> q;	//用map来记录字符串是否出现过
		while(1){
			ans++;	//记录操作的次数
			sum = 0;	//记录字符串的位数
			for(i = 0; i < l; i++){
				s[sum++] = b[i];	//s2先拼凑
				s[sum++] = a[i];	
			}
			s[sum] = '\0';	//终止字符串的拼凑
			if(strcmp(s, c) == 0) break;	//字符串已经跟目标字符串相同
			if(q[s] == 1){	//如果之前出现过这个字符串
				p = 1;	//接下来会是循环操作,永远得不到目标字符串
				break;
			}
			q[s] = 1;	//标记这个字符串出现过
			for(i = 0; i < l; i++){	//把字符串分割成前后两半
				a[i] = s[i];
				b[i] = s[i + l];
			}
			a[i] = b[i] = '\0';	
		}
		printf("%d ", j);
		if(!p) printf("%d\n", ans);	//输出得到目标字符串所需的操作次数
		else printf("-1\n");	
	}		
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值