P1470 [USACO2.3]最长前缀 Longest Prefix

题目描述
在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。生物学家对于把长的序列分解成较短的序列(即元素)很感兴趣。

如果一个集合 P 中的元素可以串起来(元素可以重复使用)组成一个序列 ss ,那么我们认为序列 ss 可以分解为 P 中的元素。元素不一定要全部出现(如下例中 BBC 就没有出现)。举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素:{A,AB,BA,CA,BBC}

序列 s 的前面 kk 个字符称作 s 中长度为k 的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列 ,设 s’
是序列 s 的最长前缀,使其可以分解为给出的集合 PP 中的元素,求 s’的长度 k。

输入格式
输入数据的开头包括若干个元素组成的集合 O,用连续的以空格分开的字符串表示。字母全部是大写,数据可能不止一行。元素集合结束的标志是一个只包含一个 . 的行,集合中的元素没有重复。

接着是大写字母序列 s ,长度为,用一行或者多行的字符串来表示,每行不超过 76个字符。换行符并不是序列 s 的一部分。

输出格式
只有一行,输出一个整数,表示 S 符合条件的前缀的最大长度。

分析
一道字符串匹配再加上状态转移的题
有若干个字符串元素, 还有一个长的字符串s。
要求在s中,从前往后都能够有相应的子字符串相匹配。
用set集合来存元素,count函数判断是否找的到
dp存状态,前i长度都能匹配,为真

看不太懂我说的,再看看代码应该能懂了。

#include<bits\stdc++.h>
using namespace std;
int dp[200005], m;
//dp前面i长度的子序列都能分解 
set<string> s[20];
int main() {
    
    
  string tp;
  while (cin >> tp) {
    
    
    if (tp == ".") break;
    s[tp.size()].insert(tp);
    m = max(m, int(tp.size()));
  }
  int i, ans = 0;
  dp[0] = 1;
  string n;
  n = " ";
  while (cin >> tp) {
    
     //可能不止一行 全加上 
    n = n+tp;
  }
  for (i = 1; i < n.size(); i++) {
    
    //前面 k 个字符
    for (int j = min(i, m); j >= 1; j--) {
    
    
      string tt = n.substr(i-j+1, j);
      //取出从i-j+1位置长度为j的字符串 
      if (s[tt.size()].count(tt) == 1 && dp[i-j] == 1) {
    
    
        ans = i;
        dp[i] = 1;
        break; // j是从大往小走,肯定是最大的 
      }
    }
  }
  cout << ans;
  return 0;
}

(`・ω・´)
structure
n. 结构; 构造; 结构体; (尤指) 建筑物; 精心组织; 周密安排; 体系;
v. 使形成体系; 系统安排; 精心组织;

猜你喜欢

转载自blog.csdn.net/plutozxc/article/details/109034029