poj3007

12 篇文章 0 订阅
3 篇文章 0 订阅

题目不难。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;
}
		


   

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值