HDU1560 DNA sequence(迭代加深搜索)

题意:给你一些字符串\(s_0, ...,s_{n-1}\),求一个串S,S要把\(s_0\)\(s_{n-1}\)包括进来,输出S的最短长度

包括的意思是:对于串\(s_i,i=0,...,n, s_i\)\(S\)的最长公共子序列为\(s_i\)

一开始的想法是这样的:从前向后遍历每个串,对于每一个串\(s_i\),求一下\(s_0,...s_{i-1}\)\(s_i\)的最长公共子序列长度的最大值maxv,然后将总长度sum加上\(len(s_i) - maxv\),最后输出sum,这个方法乍一看好像很对,用了贪心,但是事实上搞不到最优解...

思路:正确思路是迭代加深搜索,就是dfs外面套一层循环,用来规定dfs最大深度值,这种方法在找最优解的时候很有用,只要在某一个深度找到了解,那么就是最优解,而且还可以避免在不可能找到解的分支上越走越远(因为限定了深度)

注意:由于本题时间限制为0.5s,所以还需要剪枝,每一次递归判断一下如果当前递归层数 + 最少还需要递归的层数(当前所有串中剩余比较长度的最大值)> 迭代的最大深度,就说明不行

另外的话,如果dfs找到答案,就退出循环,直接输出深度d就行了
假设在限制深度为d时dfs返回1,说明找到了答案,并且答案所在的层数<=d,假设答案所在层数<d, 那么由于是迭代加深搜索,所以一定会在某一个\(d_1(<d)\)的时候就找到了答案,又因为到在\(d_1\)是dfs返回0,所以矛盾,所以答案所在层数一定是d, 因为每递归一层串长+1,所以答案的长度就是d

#include<iostream>
#include<string>
#include<vector>

using namespace std;

const int N = 10;

char c[] = {'A', 'C', 'G', 'T'};
vector<string> str;
int n;

int dfs(int u, int d, int p1[]){
    if(u > d) return 0;
    
    int maxv = 0;
    for(int i = 0; i < n; i ++) maxv = max(maxv, (int) str[i].size() - p1[i]);
    
    if(u + maxv > d) return 0;
    
    for(int i = 0; i < 4; i ++){
        int p2[10], st = 1;
        for(int j = 0; j < n; j ++){
            if(p1[j] >= str[j].size()){
                p2[j] = p1[j];
                continue;
            }
            if(str[j][p1[j]] == c[i]){
                p2[j] = p1[j] + 1;
            }
            else p2[j] = p1[j];
            st = 0;
        }
        if(st || dfs(u + 1, d, p2)) return 1;
    }
    
    return 0;
}

int main(){
      int t;
      cin >> t;
      while(t --){
          str.clear();
          cin >> n;
          for(int i = 0; i < n; i ++){
              string s;
              cin >> s;
              str.push_back(s);
          }
          
          int d = 0, p[10] = {0};
          while(1){
              d ++;
              if(dfs(0, d, p)) break;
          }
          cout << d << endl;
      }
      
      return 0;
}
posted @ 2021-10-01 15:37  yys_c  阅读(22)  评论(0编辑  收藏  举报