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\n"),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\n"),0;
    printf("YES\n");
    for (int i=0;i<ans.size();i++) printf("%d ",ans[i]);
}

 

posted @ 2021-01-30 16:09  zlc0405  阅读(248)  评论(1编辑  收藏  举报