POJ3349
http://poj.org/problem?id=3349
暴力(TLE)
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include <set>
#include <map>
#include<list>
#include <stack>
#include <queue>
#include <vector>
#include <ctime>
#define ll long long
#define f(i,a,b) for(int i=a;i<=b;i++)
#define m(a,b) memset(a,b,sizeof(a))
#define MAX 0x3f3f3f3f
const ll MOD=1e+9+7;
using namespace std;
bool ISsame(int s1[],int s2[])
{
int start=0,step=1;
bool flag=1;
f(i,0,5){
if(s2[i]==s1[0]){
flag=0;
start=i;
break;
}
}
if(flag)return false;
if(s1[1]==s2[(start-1+6)%6])step=-1;
else if(s1[1]!=s2[(start+1)%6])return false;
f(i,1,5){
start+=step;
if(start>5)start%=6;
else if(start<0)start=(start+6)%6;
if(s1[i]!=s2[start])return false;
}
return true;
}
bool All(int s[][6],int n)
{
f(i,0,n-2){
f(j,i+1,n-1){
bool pd=0;
pd=ISsame(s[i],s[j]);
if(pd)return true;
}
}
return false;
}
int main()
{
int n;
cin>>n;
int s[100010][6];
m(s,0);
f(i,0,n-1)
f(j,0,5){
scanf("%d",&s[i][j]);
}
bool ans=All(s,n);
if(!ans){
printf("No two snowflakes are alike.\n");
}
else {
printf("Twin snowflakes found.\n");
}
return 0;
}
哈希表进阶
根据具体问题思考如何构造哈希表,从而优化搜索。
AC代码1
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1200010;
const int H = 1200007;
struct Node
{
int num[6];
int next;
};
Node node[N];
int cur;
int hashTable[H];
void initHash()
{
cur = 0;
for (int i = 0; i < H; ++i) hashTable[i] = -1;
}
unsigned int getHash(int* num)
{
unsigned int hash = 0;
for (int i = 0; i < 6; ++i)
{
hash += num[i];
}
return hash % H;
}
bool cmp(int* num1, int* num2)
{
for (int i = 0; i < 6; ++i)
{
if (num1[i] != num2[i]) return false;
}
return true;
}
void insertHash(int* num, unsigned int h)
{
for (int i = 0; i < 6; ++i) node[cur].num[i] = num[i];
node[cur].next = hashTable[h];
hashTable[h] = cur;
++cur;
}
bool searchHash(int* num)
{
unsigned h = getHash(num);
int next = hashTable[h];
while (next != -1)
{
if (cmp(num, node[next].num)) return true;
next = node[next].next;
}
insertHash(num, h);
return false;
}
int main()
{
int num[2][12];
int n;
bool twin = false;
initHash();
scanf("%d", &n);
while (n--)
{
for (int i = 0; i < 6; ++i)
{
scanf("%d", &num[0][i]);
num[0][i + 6] = num[0][i];
}
if (twin) continue;
for (int i = 0; i < 6; ++i)
{
num[1][i + 6] = num[1][i] = num[0][5 - i];
}
for (int i = 0; i < 6; ++i)
{
if (searchHash(num[0] + i) || searchHash(num[1] + i))
{
twin = true;
break;
}
}
}
if (twin) printf("Twin snowflakes found.\n");
else printf("No two snowflakes are alike.\n");
return 0;
}
AC代码2
#include<iostream>
using namespace std;
const __int64 prime=999983; // 10n内最大的素数(本题n=10W)
class
{
public:
__int64 len[6]; //6瓣叶子的长度
}leaf[100001];
typedef class HashTable
{
public:
__int64 len[6]; //记录6瓣叶子的长度信息
HashTable* next; //用于冲突时开放寻址
HashTable() //Initial
{
next=0;
}
}Hashtable;
Hashtable* hash[prime+1];
/*计算第k个雪花的关键字key*/
__int64 compute_key(int k)
{
__int64 key=0;
for(int i=0;i<6;i++)
{
key+=(leaf[k].len[i]) % prime;
key%=prime; //利用同余模定理计算key,避免出现大数
}
return ++key; //键值后移1位,把key的范围从0~999982变为 1~999983
}
/*从顺时针方向判断两片雪花是否相同*/
bool clockwise(Hashtable* p,int k)
{
for(int j=0;j<6;j++) //顺时针转动j格
{
bool flag=true;
for(int i=0;i<6;i++)
if(leaf[k].len[i] != p->len[(i+j)%6])
{
flag=false;
break;
}
if(flag)
return true;
}
return false;
}
/*从逆时针方向判断两片雪花是否相同*/
bool counterclockwise(Hashtable* p,int k)
{
for(int j=0;j<6;j++) //逆时针转动j格
{
bool flag=true;
for(int i=0;i<6;i++)
if(leaf[k].len[i] != p->len[(5-i-j+6)%6])
{
flag=false;
break;
}
if(flag)
return true;
}
return false;
}
/*把第k个雪花信息插入HashTable*/
/*当插入的位置已存在其他雪花信息时,顺便比较*/
bool insert(int k)
{
__int64 key=compute_key(k);
if(!hash[key])
{
Hashtable* temp=new Hashtable;
for(int i=0;i<6;i++)
temp->len[i]=leaf[k].len[i];
hash[key]=temp; //保存key对应的地址
}
else //地址冲突,开放寻址,顺便比较
{
Hashtable* temp=hash[key];
if(clockwise(temp,k) || counterclockwise(temp,k)) //检查雪花是否相同
return true;
while(temp->next) //寻址
{
temp=temp->next;
if(clockwise(temp,k) || counterclockwise(temp,k)) //检查雪花是否相同
return true;
}
temp->next=new Hashtable; //申请空间,保存新雪花信息
for(int i=0;i<6;i++)
temp->next->len[i]=leaf[k].len[i];
}
return false;
}
int main(int i,int j)
{
int n; //雪花数
while(cin>>n)
{
/*Initial*/
memset(hash,0,sizeof(hash)); // 0 <-> NULL
/*Input*/
bool flag=false; //记录输入过程中是否出现了相同的雪花
for(i=1;i<=n;i++)
{
for(j=0;j<6;j++)
scanf("%I64d",&leaf[i].len[j]);
/*Hash*/
if(!flag) //当前还没有出现相同的雪花
flag=insert(i);
//若出现相同的雪花,则还需后续输入,但不再处理
}
/*Output*/
if(flag)
cout<<"Twin snowflakes found."<<endl;
else
cout<<"No two snowflakes are alike."<<endl;
}
return 0;
}