zoukankan      html  css  js  c++  java
  • 1476E.Pattern Matching(字典树+拓扑排序)

    您将得到n个模式p1,p2,…,pn和m个字符串s1,s2,…,sm。每个模式pi包含k个字符,这些字符可以是小写拉丁字母或通配符(用下划线表示)。所有模式都是成对的。每个字符串sj包含k个小写拉丁字母。

    如果bi从1到k中的每个i是通配符或bi = ai,则字符串a与模式b匹配。

    要求您以第j个字符串匹配的第一个模式为p [mtj]的方式重新排列模式。您可以保留模式顺序不变。

    可以进行这样的重新排列吗?如果可以,则打印任何有效订单。

    题意不太好懂,懂了之后就是常规套路,从哪里跌倒就从哪里爬起来。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+100;
    int n,m,k;
    string p[maxn];
    struct node {
        string s;
        int tk,p;
        bool operator < (const node &r) const {
            return tk<r.tk;
        }
    }Node[maxn];
    vector<int> g[maxn];
    vector<int> l[maxn];
    int inDegree[maxn];
    int Trie[maxn][30];
    int tot=0;
    void insert (int i,int pp,int rt) {
        //p表示插入起点
        if (pp==p[i].size()) {
            g[rt].push_back(i);
            return;
        } 
        if (p[i][pp]=='_') {
            for (int j=0;j<26;j++) {
                if (!Trie[rt][j]) Trie[rt][j]=++tot;
                insert(i,pp+1,Trie[rt][j]);
            }
        }
        else {
            int tt=p[i][pp]-'a';
            if (!Trie[rt][tt]) Trie[rt][tt]=++tot;
            insert(i,pp+1,Trie[rt][tt]);
        }
    }
    int find (int k) {
        int rt=0;
        for (int i=0;i<Node[k].s.size();i++) {
            int x=Node[k].s[i]-'a';
            if (!Trie[rt][x]) return 0;
            rt=Trie[rt][x];
        }
        l[k]=g[rt];
        return 1;
    } 
    int main () {
        scanf("%d%d%d",&n,&m,&k);
        for (int i=1;i<=n;i++) cin>>p[i];
        for (int i=1;i<=m;i++) cin>>Node[i].s>>Node[i].tk,Node[i].p=i;
        for (int i=1;i<=n;i++) insert(i,0,0);
        for (int i=1;i<=m;i++) {
            int x=find(i);
            if (x==0) {
                return printf("NO"),0;
            }
        }
        //每个字符串有对应的匹配集合l(i)
        //每个字符串第一个匹配的串应当是p(tk)
        //每个字符串的匹配集合,p(tk)和剩下的串连单向边
        //做拓扑排序
        for (int i=0;i<1e6;i++) g[i].clear();
        for (int i=1;i<=m;i++) {
            int f=0;
            for (int j=0;j<l[i].size();j++) if (l[i][j]==Node[i].tk) f=1;
            if (!f) return printf("NO
    "),0;
            for (int j=0;j<l[i].size();j++) {
                if (l[i][j]==Node[i].tk) continue;
                g[Node[i].tk].push_back(l[i][j]);
                inDegree[l[i][j]]++;
            } 
        }
        vector<int> ans;
        queue<int> q; 
        for (int i=1;i<=n;i++) if (inDegree[i]==0) q.push(i); 
        while (q.size()) {
            int u=q.front();
            q.pop();
            ans.push_back(u);
            for (int i=0;i<g[u].size();i++) if (--inDegree[g[u][i]]==0) q.push(g[u][i]);
        }
        if (ans.size()!=n) return printf("NO
    "),0;
        printf("YES
    ");
        for (int i=0;i<ans.size();i++) printf("%d ",ans[i]);
    }
  • 相关阅读:
    礼物的最大价值
    复杂链表的复制
    全排列(回溯法)
    删除排序数组中的重复项
    三角形最小路径和(经典dp)
    链表中倒数第k个节点
    造成segment fault,产生core dump的可能原因
    wmpnetwk.exe怎么禁启动
    GSM/GPRS/EDGE/WCDMA/HSDPA/HSUPA--辨析
    OSI七层参考模型每一层都有哪些协议
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14349357.html
Copyright © 2011-2022 走看看