SPOJ33&POJ1934 Trip DP、枚举

题目传送门:https://www.luogu.org/problemnew/show/SP33

题目大意:给出两个字符串,求其LCS(最长公共子序列)的长度与具体方案(相同的串算作同一方案)。数据组数$\leq 10$,字符串长度$\leq 80$,方案数$\leq 1000$



本来以为这是一道LCS水题,结果超级low的各种输出方案的方法TLE到怀疑人生

于是一个高大上的输出方法出现(借鉴于https://blog.csdn.net/gg_gogoing/article/details/41170117

多开两个辅助数组$f_{i,j}$与$g_{i,j}$代表$s1$与$s2$从第$1$个字符到第$i$个字符中字符$j$($a$对应$0$,$b$对应$1$,以此类推)最后一次出现的位置,计算完这两个数组之后,进行递归输出,同时使用枚举法,从后往前一个一个枚举当前位置可填的字母。
设$dfs( a , b , c)$表示当前$s1$的长度为$a$,$s2$的长度为$b$,待枚举的字母数量为$c$时的枚举过程,枚举$0-25$,得到该字母的$f_{a,b}$与$g_{a,b}$,如果当$s1$长度为$f_{a,b}$,$s2$长度为$g_{a,b}$时的最长公共子序列长度正好为$c$,则$dfs(f_{a,b} - 1 , g_{a,b} - 1 , c - 1)$,枚举完第一位后即得到一种满足题意的字符串

为何这样子可以大量剪枝?举例:

$abcabcaa$
$acbacba$

上面是样例数据,最长公共子序列长度为$5$。考虑$dfs(7,6,5)$时枚举到$a$(字符串从$0$开始标号),此时$f = 7 , g = 6$,会进行$dfs(6,5,4)$。如果不考虑上述枚举,我们的可选方案有$(0,0)(0,3)(0,6)(3,0)(3,3)(3,6)(6,0)(6,3)(6,6)(7,0)(7,3)(7,6)$共$12$种,因为相同的串算作同一方案,由贪心可以知道$(7,6)$是当前的最优选择,可以包含其他的所有情况,所以只需要向$(7,6)$继续搜索即可。

#include<bits/stdc++.h>
using namespace std;
string s1 , s2;
vector < string > s;
short maxN[81][81] , last1[26][81] , last2[26][81] , cou;
//last1、last2对应上面的f、g。
inline int max(int a , int b){
    return a > b ? a : b;
}
void create(int a1 , int a2 , int num , string ss){
    if(num == 0){
        s.push_back(ss);
        return;
    }
    for(int i = 0 ; i < 26 ; i++)
        if(last1[i][a1] >= num && last2[i][a2] >= num && maxN[last1[i][a1]][last2[i][a2]] == num)
            create(last1[i][a1] - 1 , last2[i][a2] - 1 , num - 1 , (char)(‘a‘ + i) + ss);
            //递归输出最重要的过程!!!
}
int main(){
    ios::sync_with_stdio(0);
    int T;
    for(cin >> T ; T ; T--){
        memset(maxN , 0 , sizeof(maxN));
        memset(last1 , 0 , sizeof(last1));
        memset(last2 , 0 , sizeof(last2));
        cin >> s1 >> s2;
        for(int i = 1 ; i <= s1.size() ; i++)
            for(int j = 1 ; j <= s2.size() ; j++){
                if(s1[i - 1] == s2[j - 1])    maxN[i][j] = max(maxN[i][j] , maxN[i - 1][j - 1] + 1);
                maxN[i][j] = max(maxN[i][j] , max(maxN[i - 1][j] , maxN[i][j - 1]));
            }
            //LCS DP求解
        for(int i = 1 ; i <= s1.size() ; i++)
            for(int j = 0 ; j < 26 ; j++)
                if(s1[i - 1] - ‘a‘ == j)    last1[j][i] = i;
                else    last1[j][i] = last1[j][i - 1];
        for(int i = 1 ; i <= s2.size() ; i++)
            for(int j = 0 ; j < 26 ; j++)
                if(s2[i - 1] - ‘a‘ == j)    last2[j][i] = i;
                else    last2[j][i] = last2[j][i - 1];
        create(s1.size() , s2.size() , maxN[s1.size()][s2.size()] , "");
        sort(s.begin() , s.end());
        for(int i = 0 ; i < s.size() ; i++)    cout << s[i] << endl;
        //输出
        s.clear();
        cout << endl;
        cou = 0;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Itst/p/9748883.html

时间: 2024-10-11 14:43:40

SPOJ33&POJ1934 Trip DP、枚举的相关文章

11825 - Hackers&#39; Crackdown 状态压缩 dp 枚举子集

11825 - Hackers' Crackdown 状态压缩 dp 枚举子集 ACM 题目地址:11825 - Hackers' Crackdown 题意: 有一个由编号0~n-1的n台计算机组成的网络,一共有n种服务,每台计算机上都运行着全部服务,对于每台计算机,你可以选择停止一项服务,这个行为会导致与这台计算机和与他相连的其他计算机上的这项服务都停止(原来已经停止的继续保持停止状态).求最多能使多少个服务瘫痪(即没有任何一台计算机在运行这项服务). 分析: 题目说白了,就是: 把n个集合p

UVA 11825 - Hackers&amp;#39; Crackdown 状态压缩 dp 枚举子集

UVA 11825 - Hackers' Crackdown 状态压缩 dp 枚举子集 ACM 题目地址:11825 - Hackers' Crackdown 题意: 有一个由编号0~n-1的n台计算机组成的网络,一共同拥有n种服务,每台计算机上都执行着所有服务,对于每台计算机,你能够选择停止一项服务,这个行为会导致与这台计算机和与他相连的其它计算机上的这项服务都停止(原来已经停止的继续保持停止状态). 求最多能使多少个服务瘫痪(即没有不论什么一台计算机在执行这项服务). 分析: 题目说白了.就

UVa 11825 - Hackers&#39; Crackdown DP, 枚举子集substa = (substa - 1)&amp;sta 难度: 2

题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2925 题意 n个节点,每个节点都有完全相同的n项服务. 每次可以选择一个节点,破坏该节点和相邻节点的某项服务. 问最多能完全破坏多少服务? 思路 如刘书, 直接枚举状态的子集 注意元素个数为k的集合有C^k_n个子集,那么枚举的时间复杂度为sum{c^k_n * 2^k} = 3^n

[HDOJ6156] Palindrome Function(数位dp, 枚举)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6156 题意:算十进制下数字在[L,R]内用[l,r]进制表述下的数字贡献. 贡献有两种:回文数,贡献是进制k:不是回文数,贡献是1. 由于进制只有36个,枚举进制分别做统计回文数的数位dp即可,贡献按要求. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 const int maxn = 1

hdu 6049---Sdjpx Is Happy(区间DP+枚举)

题目链接 Problem Description Sdjpx is a powful man,he controls a big country.There are n soldiers numbered 1~n(1<=n<=3000).But there is a big problem for him.He wants soldiers sorted in increasing order.He find a way to sort,but there three rules to obe

POJ2479【DP 枚举】

题意:给出一串数字,求出其中不重不交的两个子串的和的最大值 思路:最近最大子串和做多了,感觉这题有点水.枚举分割点,将序列分成左右两串,然后看左右串的最大子串和的最大值. //poj2479 #include<cstdio> #include<string.h> #include<iostream> #define inf 19941117 using namespace std; const int maxn=50009; int maxf(int a,int b)

UVA 11825 Hackers’ Crackdown 状压DP枚举子集势

Hackers’ Crackdown Miracle Corporations has a number of system services running in a distributed computer system which is a prime target for hackers. The system is basically a set of N computer nodes with each of them running a set of Nservices. Note

codeforces 629C Famil Door and Brackets (dp + 枚举)

题目链接: codeforces 629C Famil Door and Brackets 题目描述: 给出完整的括号序列长度n,现在给出一个序列s长度为m.枚举串p,q,使得p+s+q是合法的括号串,长度为n,问p,q的取值数目. 解题思路: 枚举p的长度,可以直接得到q的长度.因为要满足在任意位置'(' 数目大于 ’)‘ 的数目,所以统计一下s串中 ’(‘ - ')' 的最小数目minx.dp[i][j] 代表 到位置 i 时,满足 '(' - ')' == j 的情况数目.然后枚举p的 j

POJ1934:Trip(LCS)

Description Alice and Bob want to go on holiday. Each of them has planned a route, which is a list of cities to be visited in a given order. A route may contain a city more than once. As they want to travel together, they have to agree on a common ro