POJ-3349: Snowflake Snow Snowflakes
keyword
ハッシュテーブル C++
問題概要
N(<10^5)個のデータが与えられる。同じものがあるかどうか判定する問題。データは長さ6の配列で与えられ、reverse(), rotate()を使って一致するものは同じだと考える。
解法
前の記事にしたがってそのまま実装する。メモリ制限が64MBのとき確保できる32bitの配列のサイズは2^23が目安。安全を取って今回はサイズを2^22とした。このとき、特定のひとつのハッシュ値が衝突する確率はN/HASH_SIZEで、この値は1/40位。ちょっと大きくて気になるレベルだけど無視した(テストケースがよほど多くない限り基数を取り替えたら通るレベル)。実装時間16分。
感想
Eclipse+CDTを使って書いてみたけど微妙だ…。
#include <cstdio> #include <vector> #include <algorithm> using namespace std; typedef unsigned int uint; const int HASH_SIZE = 1<<22; const int MASK = HASH_SIZE - 1; const uint P1 = 1000000007; const uint P2 = 999999997; uint hash_table[HASH_SIZE]; inline uint hash(vector<uint>& t, uint P){ uint ret = 0, b = 1; for(int i=0; i<6; i++){ ret += b*(uint)t[i]; b *= P; } return ret; } inline vector<uint> getMin(vector<uint>& t){ vector<uint> ret = t; for(int k=0; k<2; k++){ for(int i=0; i<6; i++){ rotate(t.begin(), t.begin()+1, t.end()); if(ret > t){ ret = t; } } reverse(t.begin(), t.end()); } return ret; } int main(){ int n; scanf("%d", &n); vector<uint> t(6); for(int i=0; i<n; i++){ for(int j=0; j<6; j++){ scanf("%u", &t[j]); } t = getMin(t); uint hash1 = hash(t, P1)&MASK; uint hash2 = hash(t, P2); if(!hash2) hash2 = 1<<30; if(!hash_table[hash1]){ hash_table[hash1] = hash2; } else if(hash_table[hash1] == hash2){ return puts("Twin snowflakes found."), 0; } } return puts("No two snowflakes are alike."), 0; }