POJ3349,洛谷SP4354-SnowflakeSnowSnowflakes【最小表示法,hash】

正题

洛谷评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=SP4354
POJ题目链接:http://poj.org/problem?id=3349


题目大意

有n片雪花,他们6个角有不同的长度,如果两片雪花6个角长度相同(可以不同方向),那么就是两片相同的雪花,求第一个相同的雪花。


解题思路

我们可以用hash判断两片雪花是否相同,然后用每片雪花的最小表示法,这样就不需要别的判断。


code

#include<cstdio>
#include<algorithm>
#define ymm 160001
#define ull unsigned long long
int a[21],ans1,ans2,ans,n;
ull h[ymm];
using namespace std;
unsigned hash(ull x){
    unsigned pos=x%ymm,i=0;
    while (i<ymm&&h[(pos+i)%ymm]&&h[(pos+i)%ymm]!=x) i++;
    return (pos+i)%ymm;
}//哈希表
void small()//最小表示法
{
    int i=7,j=8,k;
    while(i<=12&&j<=12){
        for(k=0;k<=6&&a[i+k]==a[j+k];k++);
        if(k==6) break;
        if(a[i+k]>a[j+k]){
            i+=k+1;
            if(i==j) i++;
        }
        else{
            j+=k+1;
            if(i==j) j++;
        }
    }//正序
    ans1=min(i,j);
    i=12,j=11;
    while(i>=7&&j>=7){
        for(k=0;k<=6&&a[i-k]==a[j-k];k++);
        if(k==6) break;
        if(a[i-k]>a[j-k]){
            i-=k+1;
            if(i==j) i--;
        }
        else{
            j-=k+1;
            if(i==j) j--;
        }
    }//逆序
    ans2=max(i,j);
}
bool insert()
{
    small();
    int ans=ans1,x;bool f=false;
    ull sum=0;
    int i;
    for(i=0;i<6&&a[ans1+i]==a[ans2-i];i++);
    if(a[ans1+i]>a[ans2-i]) ans=ans2,f=true;
    //求顺时和逆时的最小
    if(!f)
      for(i=ans;i<ans+6;i++) sum=sum*13131+a[i];
    else
      for(i=ans;i>ans-6;i--) sum=sum*13131+a[i];
      //计算hash值
    if(h[(x=hash(sum))]==sum) return 1;
    h[x]=sum;return 0;
    //判断
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=7;j<=12;j++) scanf("%d",&a[j]),a[j-6]=a[j+6]=a[j];
        if(insert())
        {
            printf("Twin snowflakes found.");
            return 0;
        }
    }
    printf("No two snowflakes are alike.");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值