题目网址:http://poj.org/problem?id=3349
题目大意:找两片相同的雪花,这里相同的定义是雪花的序列可以顺时针也可以逆时针,并且可以是任何一个数字开头,例如: 5 4 3 2 1 6 和 1 6 5 4 3 2 以及 3 4 5 6 1 2 是同一片雪花
如果有相同的则输出:Twin snowflakes found.
否则输出:No two snowflakes are alike.
思路:不考虑顺时针和逆时针的话,同一片雪花的最小表示应该是一样的,如:1 2 3 4 5 6 和 2 3 4 5 6 1 的最小表示都是1 2 3 4 5 6 但是可以顺时针或者逆时针 比如将 1 2 3 4 5 6 反过来是 6 5 4 3 2 1按题意这两个是同一片雪花 但是 6 5 4 3 2 1 的最小表示是 1 6 5 4 3 2 1 是不同的
综上 一片雪花存两个最小表示 在查重就行了
代码如下:
#include<cstdio> #include<map> #include<algorithm> #include<cstring> using namespace std; const int maxn = 1e5+7; const int seed = 1331; typedef unsigned long long ull; const int Hash = 3e5+7; int n,x[15]; ull p; int get_min(int *s){//最小表示法的模板 int t = 6; for(int i = 1; i <= 6; i++) s[i+t] = s[i]; int i = 1,j = 2,k; while(i <= t&&j<= t){ for(k = 0; k < t && s[i+k] == s[j+k]; k++); if(k == t)break; if(s[i+k]>s[j+k]){ i+=k+1; i+=(i==j); } if(s[j+k]>s[i+k]){ j+=k+1; j+=(i==j); } }return min(i,j);//返回的是最小表示的第一个数的下标 } ull get_hash(int *s){//计算最小表示的哈希值 int index = get_min(s); ull ret = 0; for(int i = index; i <= index+6-1; i++) ret = ret*seed + s[i]; return ret; } struct hashmap{//用图来查重 本来用的map 果然超时间了 int head[Hash],nex[maxn<<2],size; ull state[maxn<<2];//注意这里是maxn的两倍 void init(){ size = 0; memset(head,-1,sizeof(head)); } bool insert(ull val){ int h = val%Hash; for(int i = head[h]; i!=-1; i = nex[i]) if(val == state[i]) return true; state[size] = val; nex[size] = head[h];//一开始-1,邻接表往前插点 head[h] = size++; return false; } } h; int main(){ int flag = 0; scanf("%d",&n); h.init(); while(n--){ for(int i = 1; i <= 6; i++) scanf("%d",&x[i]); p = get_hash(x); if(!flag)flag = h.insert(p); reverse(x+1,x+1+6); p = get_hash(x); if(!flag)flag = h.insert(p); } if(flag)printf("Twin snowflakes found.\n"); else printf("No two snowflakes are alike.\n"); return 0; }
poj3349 Snowflake Snow Snowflakes 最小表示法 + 哈希
