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]);
    }
  • 相关阅读:
    C#中如何禁止WindowsMediaPlayer双击全屏显示
    .NET中的泛型概述
    c# Windows服务管理
    C:Program不是内部或外部命令,也不是可运行的程序或批处理文件。
    Wireshark教程之二:Wireshark捕获数据分析
    Wireshark教程之一:认识Wireshark界面
    利用windows服务实现整点报时功能
    在windows服务中使用定时器
    flickity:支持触摸滑动,响应迅速的幻灯片轮播插件
    无法定位 Local Database Runtime 安装。请验证 SQL Server Express 是否正确安装以及本地数据库运行时功能是否已启用。
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14349357.html
Copyright © 2011-2022 走看看