1. 程式人生 > >bzoj3507 [Cqoi2014]萬用字元匹配

bzoj3507 [Cqoi2014]萬用字元匹配

我們將題目輸入的那個含萬用字元的串,記為萬用字元串,下面的檔名記為檔名檔名數量很少可以依次查詢。

我們先將“萬用字元串”以‘*’為界,將萬用字元串分解,得到若干子串,記為通配子串

我們將每個“通配子串”各建立一個AC自動機。

而有的通配子串可能含‘?’萬用字元,我們將再次按‘?’為界,分解這個“通配子串”,得到的子串記為“劃分子串”,然後將“劃分子串”加入該“通配子串”所在的AC自動機上(原“通配子串”就不加進去了)。

匹配檔名時,我們應按通配子串的順序依次匹配檔名,檢查該檔名是否可行,靠前的通配子串先匹配,如果某次匹配不成功,該檔名不可以匹配。特殊的,對於含‘

?’的通配子串,我們可以按下圖方式匹配。

 

還有些細節就是對於兩個萬用字元串"*ab?c""ab?c",第二個萬用字元串的a前面不允許有其它字元,我的做法是在萬用字元串的前後加上'{',也就是得到了"{*ab?c{",讀取“檔名”也這做,就可以解決。

另一個細節就是出現萬用字元子串"abc??"時,要求檔名的一段"abc"的後面還有兩個字元,我的做法是:視"??"後面為空串,加入AC自動機(這個也可以特判一下,我的做法可以看下程式碼> <,但是我的程式碼很醜啊)。

最後提一個細節就是:對於萬用字元子串可能有多個相同的劃分子串,比如"abc?abc”。然後你就知道該怎麼做了。

剩下的細節就不必討論了。

#include<bits/stdc++.h>
using namespace std;
 
#define idx(c) ((c) - 'a')
 
const int MAX_NODE = 100000 + 10;
const int MAX_SIZE = 27;
const char ocu = '{';
 
int ch[MAX_NODE + 10][MAX_SIZE], sz = 1;
vector<int> val[MAX_NODE + 10];           //vector型別的結點標記
int f[MAX_NODE + 10], last[MAX_NODE + 10];
int new_node()  {
    return sz++;
}
 
int cnt[MAX_NODE + 10];
 
struct trie {
    int root, str_cnt;
    trie()  {   root = new_node();  str_cnt = 0;    }
 
    void ins(const string &s, int v)  {
        int i, u = root;
        for(i = 0; i < s.length(); i++) {
            int c = idx(s[i]);
            if(ch[u][c] == 0)
                ch[u][c] = new_node();
            u = ch[u][c];
        }
        val[u].push_back(v);
        str_cnt++;
    }
 
    void get_fail() {
        queue<int> q;
 
        f[root] = root; last[root] = root;
        for(int i = 0; i < MAX_SIZE; i++)   {
            int &r = ch[root][i];
            if(r == 0)  r = root;
            else {
                q.push(r);
                f[r] = last[r] = root;
            }
        }
        while(!q.empty())   {
            int u = q.front();  q.pop();
            for(int i = 0; i < MAX_SIZE; i++)   {
                int &r = ch[u][i];
                if(r == 0)  {   r = ch[f[u]][i];    continue;   }
                q.push(r);
                f[r] = ch[f[u]][i];
                last[r] = val[f[r]].size() ? f[r] : last[f[r]];
            }
        }
    }
 
    bool query(const string &s, int st, int &ed)    {
        memset(cnt, 0, sizeof(cnt));
 
        int u = root;
        for(int i = st; i < s.length(); i++) {
            u = ch[u][idx(s[i])];
            int tmp = u;
 
            for(int j = 0; j < val[root].size(); j++)  {
                int k = i - val[root][j] + 1;
                if(k >= 0)  {
                    cnt[k]++;
                    if(cnt[k] == str_cnt)   return ed = i, 1;
                }
            }
 
            while(tmp != root) {
                for(int j = 0; j < val[tmp].size(); j++)  {
                    int k = i - val[tmp][j] + 1;
                    if(k >= 0)  {
                        cnt[k]++;
                        if(cnt[k] == str_cnt)   return ed = i, 1;
                    }
                }
 
                tmp = last[tmp];
            }
 
        }
        return 0;
    }
};
 
vector<trie> A;   //我將每個AC自動機存在A裡面
 
bool match(const string &s)    {    //匹配檔名
    int i, next_st = 0, next_ed;
 
    for(i = 0; i < A.size(); i++)   {   //依次匹配AC自動機
        bool ok = A[i].query(s, next_st, next_ed);
        if(ok == 0) break;
        next_st = next_ed + 1;
    }
 
    return i == A.size();
}
 
trie split(const string &s)    {   //將劃分子串加入AC自動機
    trie res;
    string tmp;
    for(int i = 0; ; i++) {
        if(i < s.length() && s[i] != '?') tmp.push_back(s[i]);
        else {
            if(i != 0)  res.ins(tmp, i);    //實現時我將認為任意一個'?'後都可以補上空串
            tmp.clear();
        }
        if(i == s.length()) break;
    }
    res.get_fail();
    return res;
}
 
void prepare(const string &s)  {   //分離出萬用字元子串然後依次建立AC自動機
    string tmp;
    for(int i = 0; i < s.length(); ) {
        while(i < s.length() && s[i] != '*')
            tmp.push_back(s[i++]);
        A.push_back(split(tmp));
        while(i < s.length() && s[i] == '*')
            i++;
        tmp.clear();
    }
}
 
char R[MAX_NODE + 10] = "{";
string buf;
 
int main()  {
    scanf("%s", R + 1);
    buf = string(R);
    buf.push_back('{');
 
    prepare(buf);
 
    int i, n;
    scanf("%d", &n);
    for(i = 1; i <= n; i++) {
        scanf("%s", R + 1);
        buf = string(R);
        buf.push_back('{');
        if(match(buf))  puts("YES");
        else puts("NO");
    }
 
    return 0;
}


相關推薦

bzoj3507 [Cqoi2014]字元匹配

我們將題目輸入的那個含萬用字元的串,記為“萬用字元串”,下面的檔名記為“檔名”,“檔名”數量很少可以依次查詢。 我們先將“萬用字元串”以‘*’為界,將“萬用字元串”分解,得到若干子串,記為“通配子串” 我們將每個“通配子串”各建立一個AC自動機。 而有的“通配子串”可能含

[Luogu P3167] [BZOJ 3507] [CQOI2014]字元匹配

洛谷傳送門 BZOJ傳送門 題目描述 幾乎所有作業系統的命令列介面(CLI)中都支援檔名的萬用字元匹配以方便使用者。最常見的萬用字元有兩個,一個是星號(*),可以匹配 0

Leetcode 44:字元匹配(超詳細的解法!!!)

給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 '?' 和 '*' 的萬用字元匹配。 '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。 說明: s 可能為空,且只包含從 a-z 的小寫字母。

D-動態規劃比遞迴快-LeetCode44-字元匹配

題目 給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 '?' 和 '*' 的萬用字元匹配。 '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。 說明: s 可能為空,且只包含從 a-z 的小寫字母。 p 可能為空,且只包含

字元匹配

給定一個字串 (s) 和一個字元模式 § ,實現一個支援 ‘?’ 和 ‘*’ 的萬用字元匹配。 ‘?’ 可以匹配任何單個字元。 ‘*’ 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。 說明: s 可能為空,且只包含從 a-z 的小寫字母。 p 可能為空,且只包含

leetcode 44. 字元匹配

給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 '?' 和 '*' 的萬用字元匹配。 '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹

【leetCode】44_字元匹配

dp: class Solution { public: bool isMatch(string s, string p) { //tag 用於dp,tag[i][j]代表s的子串s[0,i-1] 可以匹配 p的子串p[0,j-1]。

【LeetCode】44. 字元匹配

題目描述 思路(與10. 正則表示式匹配類似) dp[ i ][ j ] 表示 s 的前 i 個字元與 p 的前 j 個字元的匹配結果。 先寫邊界情況,再寫 dp 方程,若 p[ j - 1] 為 * ,dp[ i ][ j ] = dp[ i - 1][ j

leetcode 44 ---- 動態規劃(困難) :字元匹配(java)

1.  問題:給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 '?' 和 '*' 的萬用字元匹配。 '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。 說明: s 可能為空,且只包含從 a-z 的小

字元匹配_講解和python3實現

題目描述 給定一個字串 (s) 和一個字元模式 § ,實現一個支援 ‘?’ 和 ‘*’ 的萬用字元匹配。 ‘?’ 可以匹配任何單個字元。 ‘*’ 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。 說明: s 可能為空,且只包含從 a-z 的小寫字母。 p 可能

LeetCode 10 & 44 正則表示式匹配 & 字元匹配 字串匹配問題

10 正則表示式匹配 給定一個字串 (s) 和一個字元模式 (p)。實現支援 ‘.’ 和 ‘*’ 的正則表示式匹配。 ‘.’ 匹配任意單個字元。 ‘*’ 匹配零個或多個前面的元素。 匹配應該覆蓋整個字串 (s) ,而不是部分字串。 說明: s 可能為

44. 字元匹配

給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 '?' 和 '*' 的萬用字元匹配。 '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。 說明: s 可能為空,且只包含從 a-z 的小寫字母。 p

LintCode (192)字元匹配

題目 判斷兩個可能包含萬用字元“?”和“*”的字串是否匹配。匹配規則如下: '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個串完全匹配才算匹配成功。 函式介面如下: bool isMatch(const char *s, const

String、動態規劃——wildcard-matching 字元匹配

Implement wildcard pattern matching with support for'?'and'*'. '?' Matches any single character. '*' Matches any sequence of characters

LeetCode-44.字元匹配(考察點:動態規劃)

給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 '?' 和 '*' 的萬用字元匹配。 '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。 說明: s 可能為空,且只包含從 a-z 的小寫字母。 p

【每日面試題】字串字元匹配問題

題目:在一篇英文文章中查詢指定的人名,人名使用二十六個英文字母(可以是大寫或小寫)、空格以及兩個萬用字元組成(*、?),萬用字元“*”表示零個或多個任意字母,萬用字元“?”表示一個任意字母。 如:“J* Smi??” 可以匹配“John Smith” . 請用C語言實現如下

Java 字元匹配查詢檔案

============================= 字串匹配例子      String s = "*txt.*";      s = s.replace('.', '#');      s = s.replaceAll("#", "////.");      s =

字元匹配-LintCode

判斷兩個可能包含萬用字元“?”和“*”的字串是否匹配。匹配規則如下: '?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個串完全匹配才算匹配成功。 函式介面如下: b

華為code中的字串字元匹配

#define FALSE 0 #define TRUE 1 #define M 300 #include<stdio.h> #include<string.h> int equal(char *s, char *p) { char tem

python leetcode 044 字元匹配(困難)解題報告

給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 '?' 和 '*' 的萬用字元匹配。'?' 可以匹配任何單個字元。 '*' 可以匹配任意字串(包括空字串)。 兩個字串完全匹配才算匹配成功。說明:s 可能為空,且只包含從 a-z 的小寫字母。p 可能為空,且只包含