POJ 3865 - Database 字符串hash

【题意】

给一个字符串组成的矩阵,规模为n*m(n<=10000,m<=10),如果某两列中存在两行完全相同,则输出NO和两行行号和两列列号,否则输出YES

 

【题解】

因为m很小,所以对每一行枚举其中两个字符串,检查之前行中对应的两列里是否重复即可。但是如何判重。

一开始想的把字符串做成pair然后用map映射为行号,但是TLE。

后来想到用hash判重,可能是因为哈希函数不够好,还是TLE。。。

总之这道题卡了三个小时,一直TLE。

 

枚举每一列,对枚举到的那一列从小到大排序,然后找到相邻两个相等的,接着在相同行,不同列中寻找相等的字符串,如果存在表示找到解。复杂度是m^2*n*logn,处于可以接受的范围。

 

最后的方法在POJ上使用C++通过,但是G++却超时了。

曾经记得POJ有一道题是使用G++通过,C++超时,总之以后在POJ上超时了就两个编译器都试试。

 

在看别人的代码时,发现有人用了字符串hash读入:

typedef unsigned long long ULL;
ULL hash(char *s) {
    ULL res = 0;
    for(int i = 0; s[i]; ++i) {
        res *= 9837;//质数
        res += s[i];
    }
    return res;
}

这样做比较速度相当快,程序用时不到1s。

因为没有处理冲突,所以可以用这个方法水过去(笑)

 

代码:(没有用字符串hash)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#include<string>
#include<sstream>
#define eps 1e-9
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define MAXN 1005
#define MAXM 40005
#define INF 0x3fffffff
using namespace std;
typedef long long LL;
int i,j,k,n,m,x,T,ans,big,cas,num,len,nodenum,l;
bool flag;
char s[105],t[105];
int pre;
string y[10005][15];


string ex;
struct node
{
    string st;
    int i;
} G[10005];

bool cmp(node a,node b)
{
    return a.st<b.st;
}

int main()
{
    scanf("%d%d",&n,&m);
    gets(s);
    for (i=1;i<=n;i++)//读入
    {
        gets(s);
        len=strlen(s);
        s[len]=',';
        s[len+1]='\0';
        pre=0;
        num=0;
        for (j=0;j<=len;j++)
        {
            if (s[j]==',')
            {
                s[j]='\0';
                y[i][++num]=(s+pre);
                
                pre=j+1;
            }
        }
    } 
        
    for (i=1;i<=m;i++)//枚举列
    {
        for (j=1;j<=n;j++)//把这一列复制一遍后排序
        {
            G[j].st=y[j][i];
            G[j].i=j;
        }
        sort(G+1,G+1+n,cmp);
        
        
        for (j=1;j<=n;j++)//枚举行
        {
            for (k=j+1; k<=n && G[k].st==G[j].st ;k++)//向下找与第j行相同的行
            {
                for (l=i+1;l<=m;l++)//再枚举其他列,检查是否有重复
                {
                    if ( y[ G[j].i ][l]==y[ G[k].i ][l] )//存在重复
                    {
                        printf("NO\n");
                        printf("%d %d\n",G[j].i,G[k].i);
                        printf("%d %d\n",i,l);
                        return 0;
                    }
                }
            }
        }
    }
        
    printf("YES\n");
    return 0;
}

 

posted @ 2015-02-04 10:11  zhyfzy  阅读(251)  评论(0编辑  收藏  举报