• 18.06.03 POJ 4126:DNA 15年期末05(状压DP)


    描述

    考虑一段DNA单链,上面有N个基因片段。这里的基因片段可重叠(例如AGCTC包含AGC和CTC),不可倒置(例如AGCTC不包含TCG)。要问这样的单链最短长度是多少。

    输入

    输入的第一行是一个正整数T(不超过13),表示数据组数。每组数据若干行,其中第一行一个正整数N(不超过9),表示基因片段的数目,接下来N行每行一个基因片段,由AGCT四个字母组成,且长度介于1和15之间(含两端)。输出每组数据输出一样,表示最短的单链长度包含这N个基因片段。

    样例输入

    1
    5
    TCGG
    GCAG
    CCGC
    GATC
    ATCG

    样例输出

    11
     1 #include <iostream>
     2 #include <string.h>
     3 #include <algorithm>
     4 #include <cstdio>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <memory>
     8 #include <queue>
     9 
    10 using namespace std;
    11 
    12 const int maxn = 9;
    13 int f[1 << (maxn + 1)][maxn];//x为二进制表示的一维visited状态 y为当前字符串的最后一个基因片段
    14 char genes[maxn + 1][20];
    15 bool invalid[maxn + 1];
    16 int l[maxn + 1];
    17 int chong[maxn + 1][maxn + 1];
    18 int n, minlen, base;
    19 
    20 int dp(int state, int last) {
    21     if (f[state][last])
    22         return f[state][last];
    23     f[state][last] = 1 << 10;
    24     for (int i = 1; i <= n; i++) {
    25         int flag = state & (1 << i);
    26         if (invalid[i] && flag != 0) {
    27             f[state][last] = min(dp(state - (1 << i), i) + l[last] - chong[last][i], f[state][last]);
    28         }
    29     }
    30     return f[state][last];
    31 }
    32 
    33 int main()
    34 {
    35     int t;
    36     scanf("%d", &t);
    37     while (t--) {
    38         scanf("%d", &n);
    39         for (int i = 1; i <= n; i++)
    40             cin >> genes[i];
    41         memset(f, 0, sizeof(int)*(1 << (maxn+1))*maxn);
    42         minlen = 2 << 10;
    43         base = 1 << (n + 1);
    44         for (int i = 1; i <= n; i++) {
    45             invalid[i] = true;
    46             f[0][i] = l[i] = strlen(genes[i]);
    47         }
    48         for (int i = 1; i <= n; i++)
    49             for (int j = 1; j <= n; j++)
    50             {
    51                 if (i != j && invalid[i] && invalid[j] && strstr(genes[i], genes[j]) != NULL)
    52                 {
    53                     invalid[j] = false;
    54                     base -= 1 << j;
    55                 }
    56                 if (i != j && invalid[i] && invalid[j]) {
    57                     int l0 = min(l[i], l[j]);
    58                     while (l0) {
    59                         if (strstr(genes[j], genes[i] + l[i] - l0) == genes[j])
    60                             break;
    61                         l0--;
    62                     }
    63                     chong[i][j] = l0;
    64                 }
    65             }
    66         for (int i = 1; i <= n; i++)
    67             if (invalid[i])
    68                 minlen = min(dp(base - (1 << i) - 2, i), minlen);
    69         printf("%d
    ", minlen);
    70     }
    71     return 0;
    72 }
    View Code

    解题思路

     f[x][y] 表示在x状态下,单链尾的基因片段是 genes[y] 时的最小长度

    x状态的表示方式:主要思想是二进制,我这里设的是如果遍历过这个基因片段i,表示状态的二进制数中的第i位(从0算起)就变为0(这就是所谓的状态压缩吧)

    然后主要是要把所有包含关系的基因片段剔除,网上搜到一个学长的代码其实是不对的,但他提供了一个很好的思路……不过也能A,说明数据还是比较弱的……

    WA点:因为我只使用x状态数中的1~n位,在写的时候就要注意把第0位(也就是1)去掉, f[x][y] 的x范围也要开到 1<<10 ,事实证明是有9个基因片段的数据的。

    然后后来因为忘改memset中的大小wa了很久……惨……

    注定失败的战争,也要拼尽全力去打赢它; 就算输,也要输得足够漂亮。
  • 相关阅读:
    【刷题-LeetCode】165 Compare Version Numbers
    python 22 内置模块2
    python 21 内置模块
    python 20 模块,包,及开发目录规范
    python 19
    python 18 三元,生成,递推
    定时抓取数据并存入数据库
    抓取财报数据
    金币
    交换座位
  • 原文地址:https://www.cnblogs.com/yalphait/p/9128319.html
Copyright © 2020-2023  润新知