蓝书(算法竞赛进阶指南)刷题记录——POJ3349 Snowflake Snow Snowflakes(最小表示法+字符串hash)

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/86405151

题目:POJ3349.
题目大意:给定雪花可以用六元组 ( a 1 , a 2 , . . . , a 6 ) (a_1,a_2,...,a_6) 来表示,现在要求你判断是否有两片雪花相同.两片雪花相同定义为它们从任意一点开始顺时针或逆时针数的六元组完全相同.

我们发现这种同构类的问题很自然地可以想到最小表示法,然后顺逆时针都可以很容易想到把原串和翻转后的串的最小表示法都存起来.

现在我们的问题就变成了如何判断是否有串相同,那么很容易想到这可以用字符串hash来做,然后就可以 O ( n ) O(n) 解决这个问题了.

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
  using namespace std;

#define Abigail inline void
typedef long long LL;
typedef unsigned long long ULL;

const int L=6,N=100000;
const ULL P=13333331,M=1000037;

ULL tmp[L*2+9];

void minimum(ULL *c,int len){
  for (int i=1;i<=len;++i)
    tmp[i]=c[i],tmp[i+len]=c[i];
  int i=1,j=2,k;
  while (i<len&&j<len){
  	for (k=0;tmp[i+k]==tmp[j+k];++k);
  	tmp[i+k]<tmp[j+k]?j=j+k+1:i=i+k+1;
  	if (i==j) ++j;
  }
  if (i>j) i=j;
  for (j=1;j<=len;++j)
    c[j]=tmp[i+j-1];
}

ULL Hash(ULL *s,int len){
  ULL ans=0;
  for (int i=1;i<=len;++i)
    ans=ans*P+s[i];
  return ans;
}

struct Hash_table{
  int h[M+9];
  ULL v[M+9];
  
  void add(ULL &a,const ULL &b){a+=b;if (a>=M) a-=M;}
  
  void insert(ULL x){
  	ULL t=x;
  	for (x%=M;h[x]&&v[x]^t;add(x,5));
  	++h[x];v[x]=t;
  }
  
  bool find(ULL x){
  	ULL t=x;
  	for (x%=M;h[x]&&v[x]^t;add(x,5));
  	return h[x]?1:0;
  }
  
}h;

void reversal(ULL *c,ULL *s,int len){
  for (int i=1;i<=len;++i)
    s[i]=c[len-i+1];
}

int n,len=6;
ULL c1[L+9],c2[L+9];

Abigail getans(){
  int flag=0;
  ULL t1,t2;
  scanf("%d",&n);
  for (int i=1;i<=n;++i){
    for (int j=1;j<=6;++j)
      scanf("%llu",&c1[j]);
    reversal(c1,c2,len);
    minimum(c1,len);minimum(c2,len);
    t1=Hash(c1,len);t2=Hash(c2,len);
    if (h.find(t1)||h.find(t2)) flag=1;
    h.insert(t1);h.insert(t2);
  }
  puts(flag?"Twin snowflakes found.":"No two snowflakes are alike.");
}

int main(){
  getans();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/86405151
今日推荐