AcWing 137 雪花 邻接表+hash

原题链接:https://www.acwing.com/problem/content/description/139/

题意:问能否在给出的雪花里找出两片相同的雪花,顺时针或逆时针相同都行。

思路:每片雪花有6个角,且每个角都有长度。那么我们可以利用设置一个hash函数来存储每片雪花的值,用snow[maxn][6]储存每片雪花的每个角的值。我们使用邻接表存储,当输入一片新的雪花时,先求出它的hash值,找到对应的表头,然后再扫描其对应的链表,挨个比对每一个角是否相同。

邻接表模板:

//加入有向边(x,y),权值为z 
void add(int x, int y,int z){
	++tot;
	ver[tot]=y;
	edge[tot]=z;
	nexxt[tot]=head[x];
	head[x]=tot;//在表头x处插入 
}

//访问从x出发的所有边
for(int i=head[x];i;i=nexxt[i]){
	int y=ver[i],z=edge[i];
	//找到了一条有向边(x,y),权值为z 
} 

hash函数相关介绍:https://blog.csdn.net/u012835097/article/details/79407591

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int n,tot,p=92083,snow[maxn][6],head[maxn],ne[maxn],a[6];;
int H(int *a){//获得hash函数值,此处定义为 (sum+mul)%p,p为小于范围的很大质数 
	int sum=0;
	ll mul=1;
	for(int i=0;i<6;i++){
		sum=(sum+a[i])%p;
		mul=mul*a[i]%p;
	} 
	return (sum+mul)%p;
}
bool equal(int *a, int *b){//只要有一个方向相同就行 
	for(int i=0;i<6;i++)
		for(int j=0;j<6;j++){
			bool flag=1;
			for(int k=0;k<6;k++){
				if(a[(i+k)%6]!=b[(j+k)%6]) flag= 0;//顺时针 
			}
			if(flag) return 1;
			flag=1;//复原 
			for(int k=0;k<6;k++){
				if(a[(i+k)%6]!=b[(j-k)%6]) flag=0;//逆时针 
			}
			if(flag) return 1;
		}
	return 0;
}
bool insert(int *a){
	int val=H(a);//数组a对应的hash值 
	//遍历表头head[val]指向的链表,寻找形状相同的雪花 
	for(int i=head[val];i;i=ne[i]){
		if(equal(snow[i],a)) return 1;
	}
	//没有找到,执行插入操作
	++tot;
	for(int i=0;i<6;i++){
		snow[tot][i]=a[i];//赋值更新 
	}
	//在表头处插入 ,邻接表 
	ne[tot]=head[val];
	head[val]=tot;
	return 0; 
} 
int main(){
	cin>>n;
	while(n--){
		for(int j=0;j<6;j++){
			cin>>a[j];
		}
		if(insert(a)){//每输入一组,就比对一下 
			puts("Twin snowflakes found.");
			return 0;
		}
	}
	puts("No two snowflakes are alike.");
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值