hdu 1880 字符串哈希

【题目描述】
据说魔法世界有100000种不同的魔咒,给你一部魔咒词典。当你听到一个魔咒时,你的程序必须说出那个魔咒的功能;当你需要某个功能但不知道该用什么魔咒时,你的程序要替你找到相应的魔咒。如果你要的魔咒不在词典中,就输出“what?”。
【输入描述】
首先列出词典中不超过100000条不同的魔咒词条,每条格式为:[魔咒] 对应功能。
其中魔咒和对应功能分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。词典最后一行以“@END@”结束,这一行不属于词典中的词条。
词典之后的一行包含正整数N(N <= 1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。
【输出描述】
每个测试用例的输出占一行,输出魔咒对应的功能,或者功能对应的魔咒。如果魔咒不在词典中,就输出“what?
—————————————以上是废话———————————————————————

先提一下题目的坑点及我的收获:
1.题目的输入会有空格,所以要注意,要用getchar(),吸收空格

2.题目给的内存挺小的,单纯的map是过不去的

3.收获了如何使用lower_bound二分寻找结构体中的数据,虽然还不是特别会。这个要在lower_bound中使用四个参数

 int k = lower_bound(key + 1, key + 1 + num, wait, cmp) - key;

其中wait是结构体类型的,cmp就是结构体的自定义排序函数,具体为什么这么写还不特别懂
4,hash并不一定要开数组,(不知道下面的return这么写的用意

ull Hash(char *s) {
    ull h = 0;
    while(*s) {
        h = h * has + (*s++);
    }
    return (h & 0x7FFFFFFF);//就是这里
}

思路:一开始有又想着套哈希模板,用map去存。发现不会做。然后在网上看到说这题可以用map水过去的,果断去试了一发,结果超内存了。最后只能老老实实的用hash来做。不知道是不能用map还是我不会,最后采用的方法是用结构体存储的。结构体有两个变量,一个是在输入顺序,一个是这个咒语的哈希值大小。大致思路就是对输入的魔咒和对应咒语保存下来,并进行哈希,保存在结构体中。最后对输入的每一组数据计算出相应的哈希值,在结构体中二分查找所对应的哈希值,如果没有就是返回“what?”有的话就是输出对应结果。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <cstring>
#include  <set>
#include <string>
using namespace std;
typedef unsigned long long ull;
const int maxn = 100005;
char a[maxn][100], b[maxn][100], c[100];
const int has = 131;
int num = 1;
struct node {
    int Hash, i;
} key[maxn], tail[maxn], wait;
bool cmp(node a, node b) {
    return a.Hash < b.Hash;
}
ull Hash(char *s) {
    ull h = 0;
    while(*s) {
        h = h * has + (*s++);
    }
    return (h & 0x7FFFFFFF);
}
void init() {
    for(int i = 1; i <= num; i++) {
        key[i].Hash = Hash(a[i]);
        key[i].i = i;
        tail[i].i = i;
        tail[i].Hash = Hash(b[i]);
    }
    sort(key + 1, key + 1 + num, cmp);
    sort(tail + 1, tail + 1 + num, cmp);
}
int main() {
    char p[] = "@END@";
    while(~scanf("%s", a[num])) {
        getchar();
        if(strcmp(a[num], p) == 0) break;
        cin.getline(b[num++],  85);
    }
    init();
    int t;
    scanf("%d", &t);
    getchar();
    while(t--) {
        gets(c);
        wait.Hash = Hash(c);
        if(c[0] == '[') {
            int k = lower_bound(key + 1, key + 1 + num, wait, cmp) - key;
            if(key[k].Hash != wait.Hash) {
                printf("what?\n");
            } else printf("%s\n", b[key[k].i]);
        } else {
            int k = lower_bound(tail + 1, tail + 1 + num, wait, cmp) - tail;
            if(tail[k].Hash != wait.Hash) {
                printf("what?\n");
            } else {
                char d[100];//要取掉[]    
                strcpy(d, a[tail[k].i]);
                int len = strlen(d);
                d[len - 1] = 0;
                printf("%s\n", d + 1);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值