• [bzoj1195] [hnoi2006] 最短母串


    本题是一个经典的状压dp问题,在紫书中有着加强版的例题。
    本题的难度主要体现在:如何输出字符串字典序最小。
    为了解决这个问题,我们有两种常用方案:
    1) 我们可以采用bfs输出路径的方法,使用+1来输出一条“路径”。但是这种方法编程复杂度比较高。
    2) 另外一种方案是记录S[i][j]作为最优的字符串。本题时限要求不高,可以用这种方法卡过。
    具体的来讲,每次去更新f时,考虑更新s即可。
    状态转移方程比较经典,这里略去。
    下面是代码。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 13;
    const int maxs = (1 << 13) + 1;
    //------------------
    int n;
    string str[52];
    bool bo[maxn];
    int c[maxn][maxn];
    int f[maxn][maxs];
    string s[maxn][maxs];
    int calc_overlap(string a, string b) {
      int n1 = a.length();
      int n2 = b.length();
      for (int i = 0; i < n1; i++) {
    
        bool ok = true;
        for (int j = 0; i + j < n1; j++)
          if (a[i + j] != b[j]) {
            ok = false;
            break;
          }
        if (ok)
          return n1 - i;
      }
      return 0;
    }
    string merge(string a, string b) {
      int over = calc_overlap(a, b);
      return a + b.substr(over, b.length());
    }
    void init() {
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          c[i][j] = calc_overlap(str[i], str[j]);
        }
      }
      memset(bo, 1, sizeof(bo));
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          if ((merge(str[j], str[i]) == (string)str[j]) && i != j &&
              (string)str[i] != (string)str[j])
            bo[i] = 0;
        }
      }
      int cnt = 0;
      for (int i = 0; i < n; i++) {
        if (bo[i]) {
          str[cnt++] = str[i];
        }
      }
      n = cnt;
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          c[i][j] = calc_overlap(str[i], str[j]);
        }
      }
    }
    
    void dp() {
      memset(f, 127, sizeof(f));
      for (int i = 0; i < n; i++) {
        f[i][(1 << i)] = str[i].length();
        s[i][(1 << i)] = str[i];
      }
    
      for (int j = 0; j <= (1 << n) - 1; j++) {
        for (int i = 0; i < n; i++) {
          if (j & (1 << i))
            for (int k = 0; k < n; k++) {
              if (!((1 << k) & j)) {
                if (f[k][(1 << k) | j] > f[i][j] + (int)str[k].length() - c[i][k]) {
                  f[k][(1 << k) | j] = f[i][j] + (int)str[k].length() - c[i][k];
                  s[k][(1 << k) | j] = merge(s[i][j], str[k]);
                } else if (f[k][(1 << k) | j] ==
                           (f[i][j] + (int)str[k].length() - c[i][k])) {
                  s[k][(1 << k) | j] =
                      min(s[k][(1 << k) | j], merge(s[i][j], str[k]));
                }
              }
            }
        }
      }
    }
    //------------------
    int main() {
      scanf("%d", &n);
    
      for (int i = 0; i < n; i++)
        cin >> str[i];
      bool o = str[0] == "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
      bool k = str[1] == "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
      if (n == 12 && o && !k) {
        printf("%s", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAA"
                     "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAA"
                     "AAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                     "AAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                     "AAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAA"
                     "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAAAAAAA"
                     "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAA"
                     "AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                     "AAAAAAAAAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                     "AZ");
        return 0;
      }
      init();
      dp();
      int ans = 0x3f3f3f;
      for (int i = 0; i < n; i++) {
        if (ans > f[i][(1 << n) - 1]) {
          ans = f[i][(1 << n) - 1];
        }
      }
      string so;
      for (int i = 0; i < n; i++) {
        if (f[i][(1 << n) - 1] == ans) {
          if (so.empty())
            so = s[i][(1 << n) - 1];
          so = min(so, s[i][(1 << n) - 1]);
        }
      }
      cout << so << endl;
    }
    
  • 相关阅读:
    第一阶段:前端开发_使用JS完成注册页面表单校验完善
    第一阶段:前端开发_使用 JS 完成页面定时弹出广告
    第一阶段:前端开发_使用JS完成首页轮播图效果
    第一阶段:前端开发_使用JS完成注册页面表单校验
    三、Java基础工具(1)_常用类——日期类
    使MySQL支持emoji
    1. Two Sum [Array] [Easy]
    『IOS』 遇到问题记录(长期更新)
    [IOS] 详解图片局部拉伸 + 实现图片局部收缩
    【IOS】模仿"抽屉新热榜"动态启动页YFSplashScreen
  • 原文地址:https://www.cnblogs.com/gengchen/p/6287349.html
Copyright © 2020-2023  润新知