题目不难。hash快速查找
大致题意为:给定一串字符,可以从中间某个位置分割为两部分,然后利用着两步分字符串组合成一个新的字符串,分割成的两个字符串可以逆序组合,也就是说对于每两个字符串,都有8种组合方式,现在要求出所有的不重合的组合方式个数。
题意很清晰。数据量也不大,字符串最多为72位,应该是水题。思路很清晰就是枚举所有可能的划分情况,然后判重,得出最后不重合的组合个数。
开始打算用STL——map+string快速解决,因为这题很明显适合用map和hash,但是提交后发现编译器不允许使用String类操作的reverse函数,编译错误。后来自己写Reverse函数结果TLE。原因也很明显!STL提供的容器操作速度还是非常慢的,所以在不能保证时间的情况下,尽量不要用map,而使用同样功能但普遍快速的hash查找。后来用hash迅速解决。
分别给出map+string代码和hash查找代码:
map+string代码,(TLE)仅供参考:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<map>
#include<vector>
#include<functional>
#define Max 80
using namespace std;
char Input[Max];
char p[Max];
int c;
string trans(string temp){
int len=temp.size();
for(int i=0;i<len;i++)
p[i]=temp.at(len-i-1);
p[len]='\0';
return string(p);
}
int cal(){
map<string,bool> cap;
int len=strlen(Input),ans=0;
for(int i=0;i<len-1;i++){
char temp=Input[i+1];
Input[i+1]='\0';
string first(Input);
Input[i+1]=temp;
string next(Input+i+1);
if(!cap[first+next]){
cap[first+next]=true;
ans++;
}
if(!cap[next+first]){
ans++;
cap[next+first]=true;
//cout << next+first << endl;
}
//cout << first+next << endl;
string help=trans(next);
//reverse(help.begin(),help.end());
if(!cap[first+help]){
ans++;
cap[first+help]=true;
//cout << first+help << endl;
}
if(!cap[help+first]){
ans++;
cap[help+first]=true;
//cout << help+first << endl;
}
help=trans(first);
//reverse(help.begin(),help.end());
if(!cap[next+help]){
//cout << next+help << endl;
ans++;
cap[next+help]=true;
}
if(!cap[help+next]){
//cout << help+next << endl;
ans++;
cap[help+next]=true;
}
//reverse(next.begin(),next.end());
next=trans(next);
if(!cap[next+help]){
ans++;
cap[next+help]=true;
//cout << next+help << endl;
}
if(!cap[help+next]){
//cout << help+next << endl;
ans++;
cap[help+next]=true;
}
}
return ans;
}
int main(){
scanf("%d",&c);
while(c--){
scanf("%s",Input);
getchar();
printf("%d\n",cal());
}
return 0;
}
下面是hash快速查找代码:1840K+266MS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define Max 80
#define prime 5987 //取最大可能存储数据个数*10以内的最大素数(本题最大为72*8=576近似为600,取6000以内的最大素数为5987)
struct Node{ // 哈希节点
char value[Max]; //字符串内容
struct Node *next;
}node[prime];
bool flag[prime]; //判断是否存在
char Input[Max]; //输入字符串
char first[Max];//分割的第一部分
char next[Max]; //分割的第二部分
char help[Max]; //转置辅助数组
char result[Max];//最后合并的字符串
int c;
void Reverse(char *str,char *obj){ //将str转置,结果存储与obj
int len=strlen(str);
for(int i=0;i<len;i++)
obj[i]=str[len-i-1];
obj[len]='\0';
}
int Strcat(char *f,char *n){ //拼接字符串f和n,结果存储与result中
result[0]='\0';
strcat(result,f);
strcat(result,n);
int key=0,len=strlen(result);
for(int i=0;i<len-1;i++) //计算key值
key+=(result[i]-result[i+1]);
return abs(key)%prime;
}
bool hash(int key){ //插入哈希表中,哈希判重
if(!flag[key]){
flag[key]=true;
strcpy(node[key].value,result);
node[key].next=NULL;
return true;
}
else{
struct Node *index=&node[key];
while(index){
if(strcmp(index->value,result)==0)
return false;
index=index->next;
}
struct Node *p=(struct Node *)malloc(sizeof(struct Node));
p->next=node[key].next;
strcpy(p->value,result);
node[key].next=p;
return true;
}
}
int cal(){ //计算总的不同组合个数
int len=strlen(Input),ans=0;
for(int i=0;i<len-1;i++){
char temp=Input[i+1];
Input[i+1]='\0';
strcpy(first,Input); //分割的第一部分
Input[i+1]=temp;
strcpy(next,Input+i+1); //分割的第二部分
if(hash(Strcat(first,next))) //枚举8中组合形式,以0表示顺序,1表示逆序,frist表示第一部分,next表示第二部分,则分别为(first0,next0)、(next0,first0)、(first,next1)、(next1,first)、(first1,next)、(next,first1)、(first1,next1)、(next1,first1)组合形式
ans++;
if(hash(Strcat(next,first)))
ans++;
Reverse(first,help);
if(hash(Strcat(help,next)))
ans++;
if(hash(Strcat(next,help)))
ans++;
Reverse(next,help);
if(hash(Strcat(first,help)))
ans++;
if(hash(Strcat(help,first)))
ans++;
Reverse(first,next);
if(hash(Strcat(help,next)))
ans++;
if(hash(Strcat(next,help)))
ans++;
}
return ans;
}
int main(){
scanf("%d",&c);
while(c--){
getchar();
scanf("%s",Input);
memset(flag,0,sizeof(flag)); //初始化为没有插入节点
printf("%d\n",cal());
}
return 0;
}