字符串哈希-POJ3349-Snowflake Snow Snowflakes
题目:
有N片雪花,每片雪花由六个角组成,每个角都有长度。
第i片雪花六个角的长度从某个角开始顺时针依次记为ai,1,ai,2,…,ai,6。
因为雪花的形状是封闭的环形,所以从任何一个角开始顺时针或逆时针往后记录长度,得到的六元组都代表形状相同的雪花。
例如ai,1,ai,2,…,ai,6和ai,2,ai,3,…,ai,6,ai,1就是形状相同的雪花。
ai,1,ai,2,…,ai,6和ai,6,ai,5,…,ai,1也是形状相同的雪花。
我们称两片雪花形状相同,当且仅当它们各自从某一角开始顺时针或逆时针记录长度,能得到两个相同的六元组。
求这N片雪花中是否存在两片形状相同的雪花。
输入格式
第一行输入一个整数N,代表雪花的数量。
接下来N行,每行描述一片雪花。
每行包含6个整数,分别代表雪花的六个角的长度(这六个数即为从雪花的随机一个角顺时针或逆时针记录长度得到)。
同行数值之间,用空格隔开。
输出格式
如果不存在两片形状相同的雪花,则输出:
No two snowflakes are alike.
如果存在两片形状相同的雪花,则输出:
Twin snowflakes found.
数据范围
1≤n≤100000,
0≤ai,j<10000000
输入样例:
2
1 2 3 4 5 6
4 3 2 1 6 5
输出样例:
Twin snowflakes found.
题意:
给 出 n 个 长 度 位 6 的 序 列 , 需 要 判 断 其 中 是 否 存 在 两 个 序 列 “ 相 似 ” 。 相 似 是 指 从 一 个 序 列 中 的 某 个 位 置 开 始 , 顺 时 针 或 逆 时 针 遍 历 该 序 列 , 得 到 的 结 果 与 另 一 序 列 相 同 。 给出n个长度位6的序列,需要判断其中是否存在两个序列“相似”。\\相似是指从一个序列中的某个位置开始,顺时针或逆时针遍历该序列,得到的结果与另一序列相同。 给出n个长度位6的序列,需要判断其中是否存在两个序列“相似”。相似是指从一个序列中的某个位置开始,顺时针或逆时针遍历该序列,得到的结果与另一序列相同。
EG:
样
例
:
4
3
2
1
6
5
,
从
1
开
始
“
逆
时
针
”
遍
历
即
可
得
到
:
1
2
3
4
5
6
,
因
此
这
两
个
序
列
相
似
。
样例:4 \ 3 \ 2 \ 1 \ 6 \ 5,从1开始“逆时针”遍历即可得到:1 \ 2 \ 3\ 4 \ 5 \ 6,因此这两个序列相似。
样例:4 3 2 1 6 5,从1开始“逆时针”遍历即可得到:1 2 3 4 5 6,因此这两个序列相似。
题解:
暴 力 做 法 就 是 对 每 一 个 序 列 都 枚 举 剩 下 的 序 列 与 之 匹 配 , 时 间 复 杂 度 O ( n 2 ) 。 暴力做法就是对每一个序列都枚举剩下的序列与之匹配,时间复杂度O(n^2)。 暴力做法就是对每一个序列都枚举剩下的序列与之匹配,时间复杂度O(n2)。
考 虑 优 化 匹 配 的 过 程 , 对 每 一 个 序 列 可 以 利 用 哈 希 表 , 以 O ( 1 ) 的 时 间 查 询 是 否 存 在 哈 希 值 相 同 的 序 列 , 若 存 在 , 再 进 一 步 按 顺 时 针 或 逆 时 针 确 认 是 否 相 似 。 整 个 过 程 的 时 间 复 杂 度 是 O ( n ) 的 。 考虑优化匹配的过程,对每一个序列可以利用哈希表,以O(1)的时间查询是否存在哈希值相同的序列,\\若存在,再进一步按顺时针或逆时针确认是否相似。整个过程的时间复杂度是O(n)的。 考虑优化匹配的过程,对每一个序列可以利用哈希表,以O(1)的时间查询是否存在哈希值相同的序列,若存在,再进一步按顺时针或逆时针确认是否相似。整个过程的时间复杂度是O(n)的。
具体落实:
①
、
用
结
构
体
带
存
储
每
个
序
列
的
6
个
权
值
,
按
“
顺
时
针
”
、
“
逆
时
针
”
重
载
′
=
=
′
。
①、用结构体带存储每个序列的6个权值,按“顺时针”、“逆时针”重载'=='。
①、用结构体带存储每个序列的6个权值,按“顺时针”、“逆时针”重载′==′。
②
、
输
入
时
对
每
一
个
序
列
求
哈
希
值
,
并
判
断
哈
希
表
中
是
否
存
在
哈
希
值
相
同
的
序
列
,
若
存
在
,
进
一
步
确
认
相
似
;
若
不
存
在
,
将
其
加
入
哈
希
表
。
②、输入时对每一个序列求哈希值,并判断哈希表中是否存在哈希值相同的序列,\\ \qquad若存在,进一步确认相似;若不存在,将其加入哈希表。
②、输入时对每一个序列求哈希值,并判断哈希表中是否存在哈希值相同的序列,若存在,进一步确认相似;若不存在,将其加入哈希表。
注意:
① 、 顺 时 针 与 逆 时 针 遍 历 的 具 体 代 码 落 实 要 熟 悉 。 ② 、 哈 希 求 值 时 , 取 模 的 值 应 当 取 的 适 当 的 小 , 且 是 质 数 , 提 高 运 行 效 率 , 因 为 也 开 不 了 太 大 的 数 组 。 ③ 、 使 用 a u t o 来 遍 历 v e c t o r 。 ①、顺时针与逆时针遍历的具体代码落实要熟悉。\\②、哈希求值时,取模的值应当取的适当的小,且是质数,提高运行效率,因为也开不了太大的数组。\\③、使用auto来遍历vector。 ①、顺时针与逆时针遍历的具体代码落实要熟悉。②、哈希求值时,取模的值应当取的适当的小,且是质数,提高运行效率,因为也开不了太大的数组。③、使用auto来遍历vector。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
#define inf 0x7fffffff
using namespace std;
const int N=1e5+10;
const int mod=99991;
int n;
struct node
{
int a[6];
bool operator == (const node &t)const
{
for(int i=0;i<6;i++)
{
if((a[0]==t.a[i%6] ///顺时针
&&a[1]==t.a[(1+i)%6]
&&a[2]==t.a[(2+i)%6]
&&a[3]==t.a[(3+i)%6]
&&a[4]==t.a[(4+i)%6]
&&a[5]==t.a[(5+i)%6])||
(a[0]==t.a[i] ///逆时针
&&a[1]==t.a[(i+5)%6]
&&a[2]==t.a[(i+4)%6]
&&a[3]==t.a[(i+3)%6]
&&a[4]==t.a[(i+2)%6]
&&a[5]==t.a[(i+1)%6])
)
return true;
}
return false;
}
};
vector<node>h[mod]; ///hash表
node A[N];
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
int sum=0;
for(int j=0;j<6;j++) {scanf("%d",&A[i].a[j]);sum+=A[i].a[j]*2;}
sum%=mod;
for(auto k:h[sum])
if(k==A[i])
{
cout<<"Twin snowflakes found."<<endl;
return 0;
}
h[sum].push_back(A[i]);
/*for(auto k:h[sum])
cout<<k.a[1]<<" ";*/
}
cout<<"No two snowflakes are alike."<<endl;
return 0 ;
}