POJ3349雪花(全新hash思路)

题目:有n朵6边形的雪花,a[1],a[2],a[3],a[4],a[5],a[6]每个编号代表每朵雪花的长度,顺时针、逆时针、反转都被视为相同的雪花,问这一堆雪花里面有没有相同的雪花?1<=n<=1e5,0<=a[i]<=10000000
感想:第二遍刷这道题,自己做了几个小时,wa了十几发,t了大二十发,终于过了,这题目真的碰撞率太大了,我用map标记都能超时,最后要开个链表才把时间卡进去,太感动了
题解:我看了一下进阶书还有网上的博客(但是看的不多可能也和大佬的思路有相同之处吧),全都是暴力顺着,倒着来搞,看不下去,然后就自己搞了一点创新。首先看了一下进阶书,因为一定是要长度相同,进阶书就直接相乘,再相加求和,为了保证六个边的长度都是一样的,然后挑选相同的hash值暴力匹配,有点点low,然后我自己找了新的思路。当然我们首先肯定要保证六条边的长度相同这是肯定的,然后我开始就想,雪花是六边形,给我的第一个感觉就是对称(图像思维),然后就莫名想到中心对称,就是你无论怎么转,怎么反转,a[1],a[2],a[3]分别与a[4],a[5],a[6]一一对应,因为中心对称,不信自己试试?然后我就把a[1]*a[4]…就衍生了另一个hash问题,就是面对另外一种问题就是,a[4]和a[1]交换怎么解决?只要解决了这个问题hash就行了。又是中心对称,在正六边形中,你把a[1],a[3],a[5]和a[2],a[4],a[6]连接两个等边三角形,你又会发现无论怎么转,都只有这两个三角形在变化,很神奇对吧?所以我就把a[1]*a[3]*a[5]+a[2]*a[4]*a[6]加到hash值,然后搞多几个质数用mp标记…然后tle了十几发,wa了十几发…这道题碰撞率太大了,本来想放弃治疗的,最后看了一下进阶书,开个链表,然后存储hash值相同的雪花试试,然后就过了,虽然不算快(玩了几个小时这道题目也累了不想搞了),但是这也是一种全新的思路。上面都是扯淡
最后修改完我的思路就是以下,其它的都加在一起,即Hash=乘积之和+和+a[1]*a[4]+a[2]*a[5]+a[3]*a[6],最后a[1]*a[3]*a[5]+a[2]*a[4]*a[6]作为两朵雪花判断是否相同的条件,然后就可以过了,只能说这道题碰撞太多了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define ull unsigned long long
#define ld long double
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rep0(i,n) for(int i=0;i<n;i++)
#define rep(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
const int mod=1e9+7;
const int maxn=1e6+7,P=1000007;
int n,a[6],b[6],head[maxn],Next[maxn],snow[maxn][6],tot=0;

int H()
{
    int s=0,k=1;
    for (int i = 0; i < 6; i++)
    {
		s=(s+a[i])%P;
		k = 1ll*k * a[i] % P;
	}
    s=1ll*(s+1ll*a[0]*a[3]%P+1ll*a[1]*a[4]%P+1ll*a[2]*a[5]%P)%P;
    return (s+k)%P;
}

bool pd(int b[],int a[])
{
    ll ans1=(1ll*a[0]*a[2]%P*a[4]%P+1ll*a[1]*a[3]%P*a[5]%P)%P;
    ll ans2=(1ll*b[0]*b[2]%P*b[4]%P+1ll*b[1]*b[3]%P*b[5]%P)%P;
    return ans1==ans2;
}

bool Insert()
{
    int val=H();
    for(int i=head[val];i;i=Next[i])
    {
        if(pd(snow[i],a))return 1;
    }
    ++tot;
    memcpy(snow[tot],a,6*sizeof(int));
    Next[tot]=head[val];
    head[val]=tot;
    return 0;
}

int main()
{
//    freopen("in.txt","r",stdin);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<6;j++)scanf("%d",&a[j]);
        if(Insert())
        {
            puts("Twin snowflakes found.");
            return 0;
        }
    }
    puts("No two snowflakes are alike.");
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值