poj 3349 (最小表示法)

开始按hash做的 交上去就wa 但是和标称拍了半天也没有不一样的 可能是生成的数据太水了吧...
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100010
#define mod 10000007
#define ll long long
using namespace std;
ll ha;
int n,a[maxn][6],base,J[7];
bool f[mod+10];
int init()
{
    int x=0,f=1;char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x*f;
}
int main()
{
    while(cin>>n)
      {
          memset(f,0,sizeof(f));int falg=0;
          for(int i=1;i<=n;i++)
          for(int j=0;j<=5;j++)
            a[i][j]=init();
         J[1]=17;J[2]=107;J[3]=117;J[4]=1007;J[5]=10007;J[6]=100007;
        base=a[1][0];
          for(int i=1;i<=n;i++)
          {
              int c[20],num=0;
              for(int j=0;j<=5;j++)
                 if(a[i][j]==base)
                  {
                    ha=0;
                    for(int k=j,r=1;r<=6;k++,r++)ha+=a[i][k%6]*J[r];
                    if(ha<0)ha=-ha;ha%=mod;c[++num]=ha;
                    ha=0;
                    for(int k=j,r=1;r<=6;k--,r++)ha+=a[i][(k+6)%6]*J[r];
                    if(ha<0)ha=-ha;ha%=mod;c[++num]=ha;
                }
              for(int j=1;j<=num;j++)
              if(f[c[j]]==1)
                 {
                  printf("Twin snowflakes found.\n");
                  falg=1;break;
                }
             if(falg)break;
               for(int j=1;j<=num;j++)f[c[j]]=1;
          }
        if(falg)continue;
        printf("No two snowflakes are alike.\n");
       }
    return 0;
}
/*
看许多人博客里说啥不用判断结构也能过....
数据有问题吧...说说正解
最小表示法  是解决同构问题的一种方法
然而并没有看懂 暴力求得(不知道为啥比标称的算法求跑的还快)
然后每个雪花用最小表示法唯一表示 最后排序找相邻的有没有相同的
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define maxn 100010
using namespace std;
int n,a[maxn][6],falg,c[6];
int init()
{
    int x=0,f=1;char s=getchar();
    while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();}
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x*f;
}
int mycmp(int *a,int *b)
{
    for(int i=0;i<6;i++)
      if(b[i]<a[i])return 1;
      else if(a[i]<b[i])return 0;
    return 0;
}
int cmp(const void *a,const void *b)
{
    int *x = (int*)a, *y = (int *)b;
    for(int i=0;i<6;i++)
      {
          if(*(x+i)<*(y+i))return -1;
        if(*(x+i)>*(y+i))return 1;
      }
    falg=1;
    return 0;
}
void Insert(int k)
{
    int ti[6];
    for(int i=0;i<6;i++)
      ti[i]=c[i];
    for(int s=0;s<6;s++)
      {
          int t[6];
          for(int i=s,r=0;r<6;r++,i++)t[r]=c[i%6];
          if(mycmp(ti,t))
          for(int i=0;i<6;i++)ti[i]=t[i];
        for(int i=s,r=0;r<6;r++,i--)
          t[r]=c[(i+6)%6];
          if(mycmp(ti,t))
          for(int i=0;i<6;i++)ti[i]=t[i];
      }
    memcpy(a[k],ti,sizeof(int)*6);
}
int main()
{
    while(cin>>n)
      {
          falg=0;
          for(int i=0;i<n;i++)
            {
                for(int j=0;j<6;j++)c[j]=init();
            Insert(i);
          }
        qsort(a,n,sizeof(a[0]),cmp);
        if(falg==1)printf("Twin snowflakes found.\n");
        else printf("No two snowflakes are alike.\n");
       }
    return 0;
}
时间: 2024-11-13 06:49:15

poj 3349 (最小表示法)的相关文章

poj 3349:Snowflake Snow Snowflakes(哈希查找,求和取余法+拉链法)

Snowflake Snow Snowflakes Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 30529   Accepted: 8033 Description You may have heard that no two snowflakes are alike. Your task is to write a program to determine whether this is really true. Y

POJ 1635 树的最小表示法/HASH

题目链接:http://poj.org/problem?id=1635 题意:给定两个由01组成的串,0代表远离根,1代表接近根.相当于每个串对应一个有根的树.然后让你判断2个串构成的树是否是同构的. 思路:首先根据01串构造出树,然后求树的最小表示法判断同构. 详情参照:https://www.byvoid.com/blog/directed-tree-bracket-sequence/ #define _CRT_SECURE_NO_DEPRECATE #include<iostream>

hash应用以及vector的使用简介:POJ 3349 Snowflake Snow Snowflakes

今天学的hash.说实话还没怎么搞懂,明天有时间把知识点总结写了,今天就小小的写个结题报告吧! 题意: 在n (n<100000)个雪花中判断是否存在两片完全相同的雪花,每片雪花有6个角,每个角的长度限制为1000000 两片雪花相等的条件: 雪花6个角的长度按顺序相等(这个顺序即可以是顺时针的也可以是逆时针的) 解题思路: hash:连加求余法 求key 值,链地址法解决冲突,连加求余法 求key 值挺简单,关于链地址法解决冲突可以通过c++中,vector容器可以较为方便的实现. 下面先介绍

HDU 4162 Shape Number(字符串,最小表示法)

HDU 4162 题意: 给一个数字串(length <= 300,000),数字由0~7构成,求出一阶差分码,然后输出与该差分码循环同构的最小字典序差分码. 思路: 第一步是将差分码求出:s[i] = (s[i] - s[i+1] + 8) % 8; 第二步是求出最小字典序的循环同构差分码,我之前没注意到字符串规模..直接用set做,MLE+TLE... 正确的方式应该是一种O(n)的解法,即最小表示法.//关于最小表示法的证明与详述请参考最小表示法:) 最小表示法算法: 初始时,i=0,j=

最小表示法(模板)

最小表示法就是对于一个循环字符串,其字典序最小的状态: 显然任意一个循环串的最小表示法是唯一的,那么可以同过比较两个循环串的最小表示法来判断它们是否相同: 对于朴素算法: 初始化:i = 0, j = 1, k = 0; 若 s[i] < s[j],j++: 若 s[i] > s[j],i = j, j++: 若 s[i] == s[j],则 k++,直至 s[i + k] != s[j + k] 对于 s[i + k] < s[j + k],j++: 否则 i = j, j++: 返回

USACO 5.5.2 字符串的最小表示法

这道题是最小表示法的一个应用, 代码如下: /* ID: m1500293 LANG: C++ PROG: hidden */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; char s[100000 + 100]; int len; int mins(char s[], int len) { int i=0, j=1, k=0; while(i<len

【枚举】【最小表示法】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game

给你一个n*m的字符矩阵,将横向(或纵向)全部裂开,然后以任意顺序首尾相接,然后再从中间任意位置切开,问你能构成的字典序最大的字符串. 以横向切开为例,纵向类似. 将所有横排从大到小排序,枚举最后切开的位置在哪一横排,将这一排提到排序后的字符串数组最前面,求个"最大表示法",如果最大表示法的位置恰好在第一排的位置,那么可以用来更新答案. 如果不在第一排的位置,那么其所构成的仍然是合法的串,而且一定不会影响答案. 这是一个最小表示法的板子. #include<cstdio>

BZOJ 2176 Strange string 最小表示法

题目大意:给定一个串S,求最小表示法 n<=1000W,实在不敢写后缀自己主动机,就去学了最小表示法= = 记得用unsigned char不然WA= = 数据真是逗- - #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10001000 using namespace std; int n; unsigned char s[

循环字符串最大最小表示法模版

循环字符串最大最小表示法模版 定义字符串abcde和cdeab同构,因为abcde转两格即为cdeab,该字符串称为循环字符串. 循环字符串的字典序最小的同构字符串称为最小表示,最大表示同理. 这里只给模版,以后再深究. int getMin(char *s) ///返回首位置 { int n=strlen(s); int i=0,j=1,k=0; while(i<n&&j<n&&k<n){ int t=s[(i+k)%n]-s[(j+k)%n]; if(