poj 3007 Organize Your Train part II(字符串哈希)

题目链接:http://poj.org/problem?id=3007

题意:给出一个字符串,从任意一个地方切开,分成两个字符串s1,s2,然后分别反转成s3,s4,然后将四个字符串任意组合(子串及其反串不可组合),求出所有不同的组合数。

如果用STL的话这题会超时,map什么的都用不了,就自己写了一个丑陋的哈希,设计的哈希函数也比较简单,47ms才过。

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
const int H=10007;
const int maxn=10010;
int hashTable[maxn],cnt;
int T;
char s[80],s1[80],s2[80],s3[80],s4[80],str[200];;

struct node{
	char str[maxn];
	int next;
}p[maxn];

void initHash();
int getHash(char *s);
void addHash(char *s,int hashNum);
bool searchHash(char *s);

void strCut(char *s,char *s1,char *s2,int index);
void strReverse(char *s1,char *s2);
void strCat(char *s1,char *s2,char *str);

int main(){
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
#endif
    scanf("%d",&T);
    while(T--){
    	initHash();
    	scanf("%s",s);
    	if(!searchHash(s)) cnt++;
    	int len=strlen(s);
    	for(int i=1;i<=len-1;i++){

    		strCut(s,s1,s2,i);
    		strReverse(s1,s3);
    		strReverse(s2,s4);

    		strCat(s1,s4,str);
			if(!searchHash(str)) cnt++;
			strCat(s3,s2,str);
			if(!searchHash(str)) cnt++;
			strCat(s3,s4,str);
			if(!searchHash(str)) cnt++;
			strCat(s2,s1,str);
			if(!searchHash(str)) cnt++;
			strCat(s2,s3,str);
			if(!searchHash(str)) cnt++;
			strCat(s4,s1,str);
			if(!searchHash(str)) cnt++;
			strCat(s4,s3,str);
			if(!searchHash(str)) cnt++;
    	}
    	printf("%d\n",cnt);
    }
    return 0;
}

int getHash(char *s){
	int hash=0,len=strlen(s);
	for(int i=0;i<len;i++)
		hash=hash+s[i]*(i+1);
	return hash%H;
}

void initHash(){
	cnt=0;
	memset(hashTable,-1,sizeof(hashTable));
}

void addHash(char *s,int hashNum){
	int len=strlen(s);
	for(int i=0;i<len;i++)
		p[cnt].str[i]=s[i];
	p[cnt].str[len]='\0';
	p[cnt].next=hashTable[hashNum];
	hashTable[hashNum]=cnt;
}

bool searchHash(char *s){
	int hashNum=getHash(s);
	int next=hashTable[hashNum];
	for(int i=next;i!=-1;i=p[i].next){
		if(!strcmp(s,p[i].str))
			return true;
	}
	addHash(s,hashNum);
	return false;
}

void strCut(char *s,char *s1,char *s2,int index){
	int len=strlen(s);
	for(int i=0;i<index;i++)
		s1[i]=s[i];
	s1[index]='\0';
	for(int i=index;i<len;i++)
		s2[i-index]=s[i];
	s2[len-index]='\0';
}

void strReverse(char *s1,char *s2){
	int len=strlen(s1);
	for(int i=0;i<len;i++)
		s2[i]=s1[len-1-i];
	s2[len]='\0';
}

void strCat(char *s1,char *s2,char *str){
	int len1=strlen(s1);
	int len2=strlen(s2);
	int index=0;
	for(int i=0;i<len1;i++)
		str[index++]=s1[i];
	for(int j=0;j<len2;j++)
		str[index++]=s2[j];
	str[index]='\0';
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值