poj.3349

这道题目题意很好理解就是在n个元素(每个元素有6个整数组成)中找是否有两个元素相同,这里的相同是指:顺时针或逆时针相同。具体看题目。那么常规的思想就是暴力了,将每个元素与其余n-1个元素比较判断。在这里每两个元素判断相等比较次数为72次,这样的话总共就要比较72×(n*n)次了,而n最大为100000,所以铁定会超时的,就用hash表查找吧!我们在10m(m=100000)范围内找一个最大的素数,做为哈希表的长度prime(注意prime的长度应该要比m大),哈希方程为key=(record)%prime+1;

其中record为每个元素6个整数的和,这样key的范围就是1到prime了,为了避免数据超出范围(这里所有数据都用__int64类型保存),有同余模定理:record[i[%prime,其中i从0到5,相加,然后对结果取一次模。用链地址法解决冲突。算法思想是:每接受一个元素的输入,就对其进行插入并判断,如果不存在该key值,则插入,继续接受输入。若存在,则进一步判断,在该key值位置的链表中是否存在某个元素与当前带插入的元素相同,若存在,则已经找到答案,接下来就只是接受完输入的问题了, 若不存在,则尾插法插入该元素。继续接受输入并判断。不断循环,直到所有的输入都已经输入完毕。然后输出相应的结果。下面简单说明一下怎么判断两个元素相等。当两个元素的key值相等时,只是说明两个元素的6个数字相加和相等,并不能说明元素相等。对!所以,我们在key值相等的情况下,还要进行相应的判断。但是反过来我们可以判定key值不相等的元素绝对不可能相等。这就是hash表的优势,将许多没有必要的比较略去了。同时,也要处理好冲突的问题。应该尽量将冲突降低。达到离散化较好的程度。最理想的情况就是:当我们比较两个元素时,他们是相等的。或者更准确的说是:他们的6个元素的和是相等的。所以这里取的prime为10m以内最大的素数。测试表明这样的离散程度最好。在来说明一下如何判读两个元素相等。由于每个元素可以是逆时针,也可以是顺时针。所以,我们可以分为对应的两种情况讨论。第一种是顺时针,另一种是逆时针,那么具体的内容看代码就很清晰了。下面是代码;

#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#define prime 999983
__int64 record[6];
bool exist[prime+1];
struct Hash{
	__int64 str[6];
	struct Hash *next;
}hash[prime+1];
int n;
__int64 Get_key(){
	__int64 t=0;
	for(int i=0;i<6;i++)
		t+=record[i]%prime;
	t%=prime;
	return t+1;
}
bool Is_clockwise(const __int64 *p,const __int64 *q){
	int i,j,k,t;
	bool trag;
	for(i=0;i<6;i++){
		t=1,j=i,k=0,trag=1;
		while(t<=6){
			if(p[j]!=q[k]){
				trag=0;
				break;
			}
			j=(j+1)%6;
			k++;
			t++;
		}
		if(trag)
			return 1;
	}
	return 0;
}
bool Is_countclockwise(const __int64 *p,const __int64 *q){
	int i,j,k,t;
	bool trag;
	for(i=0;i<6;i++){
		t=1,j=i,k=0,trag=1;
		while(t<=6){
			if(j<0)
				j=5;
			if(p[j]!=q[k]){
				trag=0;
				break;
			}
			j--;
			k++;
			t++;
		}
		if(trag)
			return 1;
	}
	return 0;
}
bool Insert(){
	__int64 key=Get_key();
	if(!exist[key]){
	    for(int i=0;i<6;i++)
			hash[key].str[i]=record[i];
		hash[key].next=NULL;
		exist[key]=1;
		return 0;
	}
	else{
		struct Hash *temp=&hash[key];
		while(temp->next!=NULL){
			if(Is_clockwise(temp->str,record))
				return 1;
			if(Is_countclockwise(temp->str,record))
				return 1;
		    temp=temp->next;
		}
		if(Is_clockwise(temp->str,record))
			return 1;
		if(Is_countclockwise(temp->str,record))
			return 1;
		struct Hash *te=(struct Hash*)malloc(sizeof(struct Hash));
		for(int i=0;i<6;i++)
			te->str[i]=record[i];
		te->next=NULL;
		temp->next=te;
		return 0;
	}
}

int main(){
	scanf("%d",&n);
	bool trag=0;
	memset(exist,0,sizeof(exist));
	while(n--){
		for(int i=0;i<6;i++)
			scanf("%lld",&record[i]);
		if(!trag)
		    trag=Insert();
	}
	if(trag)
		printf("Twin snowflakes found.\n");
	else
		printf("No two snowflakes are alike.\n");
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值