POJ 3349 数的hash

Description:

给出n个长度为6的数组,问其中是否有两个数组是同构的。当两个数组从同一个起点开始,顺着同一方向,或者反着方向循环访问,从另一侧到达起点时,两个访问的序列都相同则两数组同构。

Input:

第一行n

之后每行一个长度为6的数组。

Output:

若有相同则输出 Twin snowflakes found.

否则输出 No two snowflakes are alike.

Analysis:

问题的核心在于,给出一组数据判断是否有重构,要考虑较快速的查找和插入操作。

首先这里的数据太大,暴力会超时。然后基于一个事实,在查找表中的的元素个数最多只有100000,而可能产生的元素总数高达O(1e7^6)=O(1e42), 在这样的情况下适合用hash。通过hash函数来将所有的元素进行一个划分,在判重比较时很大一部分的元素的hash值就已经不同了,而不需要再去做更加具体的比较。这是一种加速查找判重的方式。

更加具体的,在每次读入一个数组时,直接对该数组的所有重构进行判重和插入操作。有相同的直接输出。这里的扩换成链是很常用的技巧,可以处理和数组循坏访问有关的问题。1 2 3 4 5 6 直接扩展为 1 2 3 4 5 6 1 2 3 4 5 6 这样从前六个数开始的任何连续的六个数都是它在原数组的循环访问。

hash代码:

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
int readint() { int x; cin >> x; return x; }
const int INF = 1 << 30;
const int maxn = 1200007;

int n;

const int hashsize=1200007;
int head[maxn];
struct Node{
    int num[6];
    int next;
    Node(){next=-1;}
}table[maxn];
int np;

int get_hash(int *x){
    int num=0;
    for(int i=0;i<6;++i)num=(num+x[i])%hashsize;
    return num;
}
bool cmp(int * x,int *y){
    for(int i=0;i<6;++i)if(x[i]!=y[i])return false;
    return true;
}
bool try_to_insert(int * x){

    int h=get_hash(x);
    for(int p=head[h];p!=-1;p=table[p].next){
        if(cmp(table[p].num,x))return true;
    }

    for(int i=0;i<6;++i)table[np].num[i]=x[i];
    table[np].next=head[h];
    head[h]=np;
    np++;
    return false;
}

int main()
{

	//freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
    while(~scanf("%d",&n)){
        int a1[12],a2[12];
        bool ok=false;
        np=0;
        memset(head, -1, sizeof(head));
        while(n--){
            for(int i=0;i<6;++i){
                scanf("%d",&a1[i]);
            }
            if(ok)continue;
            for(int i=0;i<6;++i)a1[i+6]=a1[i];
            for(int i=11;i>=0;--i)a2[i]=a1[11-i];
            for(int i=0;i<6;++i){
                if(try_to_insert(a1+i)||try_to_insert(a2+i)){
                    printf("Twin snowflakes found.\n");
                    ok=true;
                }
                if(ok)break;
            }
        }
        if(!ok)printf("No two snowflakes are alike.\n");
    }

	return 0;
}


猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/80291193