• 选拔赛 hash 字符串匹配 哈希算法(白书p374)


    hash
     

    Description

     

    dr所在国度的有个奇怪的规定:他们的字母不是a~z,而是用1~1000表示。

    利用这个奇怪的规定,dr想出了一个好玩的游戏:首先给出n个字符串(当然每个字符用1~1000表示),然后给出有m个节点的树,节点编号1~m,这棵树以1号节点为根,每个节点都包含一个字符。现在要求用从根节点到其他m-1个节点的链上的字符组成m-1个新字符串(字符的排列顺序为从根到终点的顺序)。

    是否这m-1个新字符串中的任意一个串,都与给出的n个字符串中至少一个串匹配呢?

    字符串S与字符串T匹配:设len1=∣S∣,len2=∣T∣len1=|S|,len2=|T|len1=S,len2=T∣,则S1=T1,S2=T2,...,Slen1=Tlen1S_{1}=T_{1},S_{2}=T_{2},...,S_{len1}=T_{len1}S1=T1,S2=T2,...,Slen1=Tlen1len1≤len2len1 leq len2len1len2

    Input

     

    第一行输入nnn和mmm,表示有nnn个字符串,树的节点数为m(n≤103,m≤2∗105)m(n leq 10^3,m leq 2 * 10^5)m(n103,m2105)

    接下来nnn行,每行首先输入一个整数kkk,代表字符串长度,然后输入kkk个整数,代表字符串Si(∣Si∣,∑∣Si∣≤2∗105)S_{i}(|Si|,sum |Si| leq 2 * 10^5)Si(Si,Si2105)

    接下来一行,输入mmm个整数CiC_{i}Ci,表示树上第iii个节点上的字符

    接下来m−1m-1m1行,每行输入2个整数u,v(1≤u,v≤m)u,v(1 leq u,v leq m)u,v(1u,vm),表示uuu和vvv有一条边

    Output

     

    输出占一行,都能匹配输出YES,否则输出NO

    Sample Input 1

    1 4
    4 1 2 3 4
    1 2 3 2
    1 2
    2 3
    1 4

    Sample Output 1

    YES

    思路:运用hash算法将字符串进行哈希,并用unordered_map储存(因为哈希的值会很大,有ull那么大,用普通的数组存不下,故考虑用map,而且没必要排序
    ,所以用unordered_map提高效率。ps:以前没用过map,这几次遇到的题用map都巨方便,运用桶排序的思维,且可以查询任意类型)。然后用dfs查询所有
    字典树出现的串的情况就OK了。
    贴一发文钧菊苣的代码
     1 #include <bits/stdc++.h>
     2 #define pb push_back
     3 using namespace std;
     4 typedef long long ll;
     5 typedef unsigned long long ull;
     6 typedef vector<int> VI;
     7 //head
     8 const int MX=2e5+7;
     9 const int has=99959;
    10 const double eps=1e-5;
    11 int n,m;
    12 int val[MX];
    13 VI E[MX];
    14 unordered_map<ull,int>vis;
    15 int dfs(int u,int fa,ull h){
    16     int res=1;//在保证了根节点满足条件的情况下的初始值
    17     for(auto v:E[u]){
    18         if(v==fa) continue;
    19         if(!vis[h*has+val[v]]){
    20             return 0;
    21         }
    22         res&=dfs(v,u,h*has+val[v]);
    23     }
    24     return res;
    25 }
    26 
    27 int main(){
    28     scanf("%d%d",&n,&m);
    29     for(int i=0;i<n;i++){//字符串总数
    30         int k;scanf("%d",&k);
    31         ull h=0;
    32         for(int j=0;j<k;j++){
    33             int x;scanf("%d",&x);//每串字符的内容
    34             h=h*has+x;
    35             vis[h]=1;//hash每串字符的前缀串并标记对应hash值
    36         }
    37     }
    38     for(int i=1;i<=m;i++) //对应字符
    39         scanf("%d",&val[i]);
    40     for(int i=1;i<m;i++){//树结构
    41         int u,v;scanf("%d%d",&u,&v);
    42         E[u].pb(v);E[v].pb(u);//建树
    43     }
    44     ull h=val[1];
    45     if(!vis[h]) puts("NO");
    46     else{
    47         if(dfs(1,-1,h)) puts("YES");
    48         else puts("NO");
    49     }
    50     return 0;
    51 }
    View Code
  • 相关阅读:
    LeetCode-62. Unique Paths
    南大算法设计与分析课程课后习题(3)
    linux-2.6.18源码分析笔记---信号
    南大算法设计与分析课程复习笔记(4)L4
    南大算法设计与分析课程复习笔记(3)L3
    南大算法设计与分析课程复习笔记(2)L2
    南大算法设计与分析课程OJ答案代码(2)最大子序列和问题、所有的逆序对
    【zz】史上最全设计模式导学目录(完整版)
    gtest学习
    全文检索及ElasticSearch框架学习
  • 原文地址:https://www.cnblogs.com/llllrj/p/9441389.html
Copyright © 2020-2023  润新知