zoukankan      html  css  js  c++  java
  • Luogu P2292 [HNOI2004]L语言

    Luogu P2292 [HNOI2004]L语言

    解析

    • 看到单词和句子匹配,再看数据范围1M的字符串(长度大约 $ 10^6 $ 级别),所以用Trie树来处理

    • 句子是没有标点符号的,所以需要我们自己断句,那么我们先将所有单词加入Trie树,然后让句子在树上匹配,匹配时可不可以匹配完一个单词就将其从句子中删掉呢?

    • 上面这个问题的回答是:NO,因为上面这个想法是一种贪心的思想,有可能会出现单词重叠后由于截取不当就不能继续向下匹配了,其实原本换种截取方法还是可以继续匹配的。举个例子:

      3 1
      abaa
      abaaa
      aaabba
      abaaaabaaabaaaaaba

      上面这个样例若用贪心的方法删完一个单词后就不能再继续匹配的情况,其实整个句子都可以匹配完

    • 那应该怎么做呢?答:两种方法 ------ 类dp 和 记忆化搜索

    方法一:类dp

    思路就是把句子上从上一个能划分的位置开始往后能连续划分单词的位置打上标记,最开始的位置是0,然后根据标记进行转移,找到最远能到达的位置即为答案

    Code

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    using namespace std;
    int n,m,rot,trie[205][26];
    char word[15],sent[1500005];
    bool book[205],vis[1500005];
    void insert(char s[])
    {
    	int u=0,len=strlen(s+1);
    	for(int i=1;i<=len;i++)
    	{
    		int v=s[i]-'a';
    		if(!trie[u][v]) trie[u][v]=++rot;
    		u=trie[u][v];
    	}
    	book[u]=1;
    	return;
    }
    int find(char s[])
    {
    	int u=0,l=0,len=strlen(s+1);
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<=len;i++)
    	{
    		int v=s[i]-'a';
    		if(!trie[u][v]) break;
    		u=trie[u][v];
    		if(book[u]) vis[i]=1;
    	}
    	for(int i=1;i<=len;i++)
    	{
    		if(!vis[i]) continue;
    		else l=i;
    		int u=0;
    		for(int j=i+1;j<=len;j++)
    		{
    			int v=s[j]-'a';
    			if(!trie[u][v]) break;
    			u=trie[u][v];
    			if(book[u]) vis[j]=1;
    		}
    	}
    	return l;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		cin>>(word+1);
    		insert(word);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		cin>>(sent+1);
    		printf("%d
    ",find(sent));
    	}
    	return 0;
    }
    

    方法二:记忆化搜索

    思路与方法一有相似之处,搜索能划分单词的位置并打上标记,每次用到达的位置更新答案即可

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    using namespace std;
    int n,m,l,rot,trie[205][26];
    char word[15],sent[1500005];
    bool book[205],vis[1500005];
    void insert(char s[])
    {
    	int u=0,len=strlen(s+1);
    	for(int i=1;i<=len;i++)
    	{
    		int v=s[i]-'a';
    		if(!trie[u][v]) trie[u][v]=++rot;
    		u=trie[u][v];
    	}
    	book[u]=1;
    	return;
    }
    void dfs(char s[],int x,int len)
    {
    	if(vis[x]) return;
    	vis[x]=1;
    	int u=0,i=x;
    	l=max(l,i-1);
    	while(i<=len)
    	{
    		int v=s[i]-'a';
    		if(!trie[u][v]) break;
    		u=trie[u][v];
    		i++;
    		if(book[u]) dfs(s,i,len);
    	}
    	return;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		cin>>(word+1);
    		insert(word);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		cin>>(sent+1);
    		l=0;
    		memset(vis,0,sizeof(vis));
    		dfs(sent,1,strlen(sent+1));
    		printf("%d
    ",l);
    	}
    	return 0;
    }
    
    Classical is something not fade,but grow more precious with time pass by,so is dream.梦想这东西和经典一样,永远不会因为时间而褪色,反而更显珍贵。
  • 相关阅读:
    每天一个linux命令:top命令
    docker入门实战笔记
    Linux top里面%CPU和us%的解释
    mac开发环境配置
    TCP/IP及内核参数优化调优
    在C#中使用代理的方式触发事件(转,这篇应该是最好的)
    如何在Vista IIS 7 中用 vs2005 调试 Web 项目? (转)
    C#接口慨述
    asp跟asp.net的区别
    解耦的故事(一)tmfc的开关(转)
  • 原文地址:https://www.cnblogs.com/Hawking-llfz/p/11472575.html
Copyright © 2011-2022 走看看