hankunyan

字符串的题目,套路不是动态规划就是转化为图。

本题把每个string作为节点,s1 -> s2 边的权值为 把s2接到s1后还需要添加的字符数量。本题就转化为类似 TSP 的问题,TSP 可以用动归来做。

复习一下TSP:

 

本题思路和 TSP 思路一致。dp 初始条件设置为 C({i},i) = A[i].size() 即可。

由于要枚举集合,方便起见,可以用二进制来表示,如 (101)_2 就表示 {2,0} 的集合。由于集合必须由size从小到大枚举,0 ~ (1<<n)-1 也刚好从小到大。[位运算优先级非常低,注意加括号!]

由于最后要返回字符串,还需要 bp 来记录 argmin 的值(也就是使得 C(S,j)最小的i的值),这样最后就可以从 min dp[(1<<n)-1][j] 一步步反推。

class Solution {
public:
    string shortestSuperstring(vector<string>& A) {
        int n=A.size();
        vector<vector<int>> g(n,vector<int>(n));
        for (int i=0;i<n;++i){
            for (int j=i+1;j<n;++j){
                g[i][j] = dist(A[i],A[j]);
                g[j][i] = dist(A[j],A[i]);
            }
        }
        for (int i=0;i<n;++i){
            for (int j=0;j<n;++j){
                cout << g[i][j] << \' \';
            }
            cout<<endl;
        }
        
        // dp(S,j) = min_i (i\in S: i!=j) dp(S-{j},i) + d_{ij}
        vector<vector<int>> dp(1<<n,vector<int>(n,INT_MAX/2));
        // backpointer, bp(S,j) = argmin_i (i\in S: i!=j) dp(S-{j},i) + d_{ij}
        vector<vector<int>> bp(1<<n,vector<int>(n,-1));
        
        for (int j=0;j<n;++j) dp[1<<j][j]=A[j].size();
        
        for (int s=1;s<(1<<n);++s){
            for (int j=0;j<n;++j){
                if (!(s & (1<<j))) continue; // j must be in S
                int prev=s-(1<<j);
                for (int i=0;i<n;++i){
                    if (!(s & (1<<i)) || i==j) continue;
                    if (dp[prev][i]+g[i][j] < dp[s][j]){
                        dp[s][j] = dp[prev][i]+g[i][j];
                        bp[s][j] = i;
                    }
                }
                // cout << s << \' \' << j << \' \'<< dp[s][j] <<endl;
            }
        }
        
        int min=INT_MAX, argmin;
        for (int j=0;j<n;++j){
            if (dp[(1<<n)-1][j] < min){
                min = dp[(1<<n)-1][j];
                argmin = j;
            }
        }

        int s=(1<<n)-1;
        int cur=argmin;
        string ans="";
        while (s){
            int prev=bp[s][cur];
            if (prev<0) ans=A[cur]+ans;
            else ans=A[cur].substr(A[cur].size()-g[prev][cur])+ans;
            s &= ~(1<<cur);
            cur = prev;
        }
        
        return ans;
    }
    
    // if put b after a, at least how many letters will be appended
    int dist(const string &a, const string &b){
        int res;
        for (int overlap=0;overlap<=min(a.size(),b.size());++overlap){
            if (a.substr(a.size()-overlap) == b.substr(0,overlap))
                res = b.size()-overlap;
        }
        return res;
    }
};

时间复杂度同 TSP

 

分类:

技术点:

相关文章:

相关资源