uva1399 - Puzzle AC自动机+记忆化搜索

Jisung is the student representative of the Department of Computer Engineering in ACM University. A few days later, the annual festival will be held for the students in the department. He is preparing some events for the festival. Since Jisung likes to make and solve puzzles, he decides to devise some interesting puzzle for the festival.

The followings are the rules for the puzzle made by Jisung:

(1)
The players will be given an integer n. Then they should use the first n capital letters from the Roman alphabet. For example, if n = 4, the four characters A, B, C, and D will be used to solve this puzzle.
(2)
The players will be given s forbidden strings. No forbidden string contains another forbidden string as a substring. The winner is the student who makes the longest string that does not include a forbidden string as a substring.
(3)
If such a longest string does not exist, i.e., if we can make arbitrarily long strings that satisfy the above condition, or if we cannot make any string that satisfies the above condition, ` No' should be answered.

For example, suppose the given number n = 2, i.e., the players can use the two charactersA and B. Assume that the forbidden strings are {AAA, AB, BA, BB}. In this case, the longest string that does not include any of the four forbidden strings as substrings isAA. But if the given forbidden strings are {AAA, BBB, ABAB, BBAA}, we cannot make such a longest string since arbitrarily long concatenations ofABA, i.e., ABAABAABA ... do not include any forbidden string.

Input 

Your program is to read from standard input. The input consists of T test cases. The number of test cases T is given in the first line of the input. Each test case starts with a line containing two integersn (1$ \le$n$ \le$26) and s (1$ \le$s$ \le$1, 000) which represent the number of characters and the number of forbidden strings, respectively. From the second line to(s + 1)-st line of the test case, the forbidden strings are given one by one. The length of a forbidden string does not exceed 50.

Output 

Your program is to write to standard output. Print exactly one line for each test case. Print the longest string that does not include any forbidden string as a substring if it exists, otherwise, just print `No' as output. When there exists more than one such longest string with the same length, print the lexicographically largest string among them.

Sample Input 

3 
2 4 
AAA 
AB 
BA 
BB 
2 4 
AAA 
BBB 
ABAB 
BBAA 
3 7 
AA 
ABA 
BAC 
BB 
BC 
CA 
CC

Sample Output 

AA 
No 
ACBAB

  找一个串包含A到A+N,这个串不包括给的一些子串,使这个串最长。如果不存在或无限长输出No。

  先用子串建立AC自动机,只要是包含那些子串的串都标记,val[u]|=val[f[u]]。这样问题变成了搜索一个最长的串不经过标记节点,并且不出现环。

  dp[u]表示在AC自动机图上从u这个点开始(不包括u)能找到的最长串,如果一个点在之前已经被访问过,也就是说dp[u]!=-1,就直接返回。那会不会u开始的最长串和当前搜索到u的这个串出现环呢?是不会的,因为u的最长串如果经过搜索到u之前的某个点,那个点的dp[u]!=-1,这个串搜到那个点的时候就已经返回了,不会搜到u了。

  用vis表示当前路径上的点,只要在搜索过程中发现环,答案就是No了。

  更新dp的时候记录路径,如果不是No的话打印路径。

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MAXN 60010
#define MAXM 2000010
#define MAXNODE 50010
#define MOD 999983
#define SIGMA_SIZE 26
typedef long long LL;
using namespace std;
int T,N,M,vis[MAXNODE],dp[MAXNODE],next[MAXNODE];
char str[100];
struct AC{
    int ch[MAXNODE][SIGMA_SIZE],f[MAXNODE],val[MAXNODE],sz;
    void init(){
        memset(ch[0],0,sizeof(ch[0]));
        val[0]=0;
        sz=1;
    }
    int idx(char c){
        return c-'A';
    }
    void insert(char *s,int v){
        int u=0;
        for(int i=0;s[i];i++){
            int c=idx(s[i]);
            if(!ch[u][c]){
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]=1;
    }
    void get_fail(){
        queue<int> q;
        f[0]=0;
        for(int c=0;c<SIGMA_SIZE;c++){
            int u=ch[0][c];
            if(u){
                f[u]=0;
                q.push(u);
            }
        }
        while(!q.empty()){
            int r=q.front();
            q.pop();
            for(int c=0;c<N;c++){
                int u=ch[r][c];
                if(!u){
                    ch[r][c]=ch[f[r]][c];
                    continue;
                }
                q.push(u);
                int v=f[r];
                while(v&&!ch[v][c]) v=f[v];
                f[u]=ch[v][c];
                val[u]|=val[f[u]];
            }
        }
    }
}ac;
int DFS(int u){
    if(vis[u]) return -1;
    int &ans=dp[u];
    if(ans!=-1) return ans;
    vis[u]=1;
    ans=0;
    for(int c=N-1;c>=0;c--){
        int v=ac.ch[u][c];
        if(!ac.val[v]){
            int tmp=DFS(v);
            if(tmp==-1) return -1;
            if(tmp+1>ans){
                ans=tmp+1;
                next[u]=c;
            }
        }
    }
    vis[u]=0;
    return ans;
}
void print(int u){
    if(next[u]!=-1){
        printf("%c",next[u]+'A');
        print(ac.ch[u][next[u]]);
    }
}
int main(){
    freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&M);
        ac.init();
        while(M--){
            scanf("%s",str);
            ac.insert(str,1);
        }
        ac.get_fail();
        memset(next,-1,sizeof(next));
        memset(dp,-1,sizeof(dp));
        memset(vis,0,sizeof(vis));
        if(DFS(0)!=-1&&dp[0]>0){
            print(0);
            puts("");
        }
        else printf("No\n");
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值