首页 > 代码库 > 51nod 简单的动态规划

51nod 简单的动态规划

1006 最长公共子序列Lcs技术分享
基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题
技术分享 收藏
技术分享 关注
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。
 
比如两个串为:
 
abcicba
abdkscab
 
ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。
Input
第1行:字符串A
第2行:字符串B
(A,B的长度 <= 1000)
Output
输出最长的子序列,如果有多个,随意输出1个。
Input示例
abcicba
abdkscab
Output示例
abca
状态转移方程为dp[i][j] = a[i]==a[j]?dp[i-1][j-1]+1:max(dp[i-1][j],dp[i][j-1]),然后用dfs搜索回去
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#pragma warning(disable:4996)
using namespace std;

char a[1005];
char b[1005];
int dp[1005][1005];
int pre[1005][1005];

void dfs(int m,int n)
{
    if(m==0||n==0)
        return;
    if(pre[m][n]==1)
    {
        dfs(m-1,n-1);
        cout<<a[m];
    }
    else if(pre[m][n]==2)
    {
        dfs(m-1,n);
    }
    else
    {
        dfs(m,n-1);
    }
}
int main()
{
    int i,j,len1,len2;
    //memset(dp,0,sizeof(dp));
    //memset(pre,0,sizeof(pre));

    cin>>a+1>>b+1;

    len1=strlen(a+1);
    len2=strlen(b+1);
    
    for(i=1;i<=len1;i++)
    {
        for(j=1;j<=len2;j++)
        {
            if(a[i]==b[j])
            {
                dp[i][j]=dp[i-1][j-1]+1;
                pre[i][j]=1;
            }
            else
            {
                if(dp[i-1][j]>dp[i][j-1])
                {
                    dp[i][j]=dp[i-1][j];
                    pre[i][j]=2;
                }
                else
                {
                    dp[i][j]=dp[i][j-1];
                    pre[i][j]=3;
                }
            }
        }
    }
    dfs(len1,len2);
    cout<<endl;
    return 0;
}
1134 最长递增子序列技术分享
基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题
技术分享 收藏
技术分享 取消关注
给出长度为N的数组,找出这个数组的最长递增子序列。(递增子序列是指,子序列的元素是递增的)
例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10。
 
Input
第1行:1个数N,N为序列的长度(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应序列的元素(-10^9 <= S[i] <= 10^9)
Output
输出最长递增子序列的长度。
Input示例
8
5
1
6
8
2
4
5
10
Output示例
5
相关问题
最长递增子序列 V2 
160
 
最长递增子序列的数量 
160
思路1:
dp[i] = MAX(a[j]<a[i])__dp[j])+1 j是0到i内小于a[i]的j,dp[i]是他们最大值加一.但是这样由于每次都要遍历前面的数组导致超时,
思路二
在这里引入一个栈,不断向其中插入新的元素,最后取栈顶位置输出纪委最长递增子序列。
在插入时应当注意,如果插入元素大于栈顶元素,那么继续进栈,否则将元素插入到lower_bound搜索得到的不小于元素键值的下标处并覆盖原键值(这里对最优解不会有影响,因为求的只是长度)。
网上的代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1E4 * 5 + 10;
int a[maxn],stk[maxn];
int main(){
        int n;
        scanf("%d",&n);
        for(int i = 1 ; i <= n ; ++i){
                scanf("%d",&a[i]);
        }
        int pcur = 0;
        for(int i = 1;i <= n;++i){
                if(!pcur){
                        stk[pcur++] = a[i];
                }else {
                        if(a[i] > stk[pcur - 1]){
                                stk[pcur++] = a[i];
                        }else if(a[i] < stk[pcur - 1]){
                                int pos = lower_bound(stk,stk + pcur,a[i]) - stk;
                                stk[pos] = a[i];
                        }
                }
        }       
        printf("%d\n",pcur);
        return 0;
}
1085 背包问题技术分享
基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题
技术分享 收藏
技术分享 关注
在N件物品取出若干件放在容量为W的背包里,每件物品的体积为W1,W2……Wn(Wi为整数),与之相对应的价值为P1,P2……Pn(Pi为整数)。求背包能够容纳的最大价值。
Input
第1行,2个整数,N和W中间用空格隔开。N为物品的数量,W为背包的容量。(1 <= N <= 100,1 <= W <= 10000)
第2 - N + 1行,每行2个整数,Wi和Pi,分别是物品的体积和物品的价值。(1 <= Wi, Pi <= 10000)
Output
输出可以容纳的最大价值。
Input示例
3 6
2 5
3 8
4 9
Output示例
14

状态转移
dp[MAXN][10000] 表示前i个物品空间为v的价值
状态转移的方程有放和不放两种,可得:
dp[i][m] = max(dp[i-1][m]__不放,dp[i-1][m-w[i]]+v[i])

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN =101;
/*
状态转移
dp[MAXN][10000] 表示前i个物品空间为v的价值
状态转移的方程有放和不放两种,可得:
    dp[i][m] = max(dp[i-1][m]__不放,dp[i-1][m-w[i]]+v[i])
*/
int dp[MAXN][10001];
int w[MAXN],v[MAXN];
int main()
{
    int n,maxw,max_all=-1;
    scanf("%d%d",&n,&maxw);
    for(int i=0;i<n;i++)
    {
        scanf("%d%d",&w[i],&v[i]);
        if(i==0)
        {
            dp[0][w[i]] = v[i];
        }
        else
        {
            for(int k=0;k<=maxw;k++)
            {
                if(k<w[i])
                    dp[i][k]=dp[i-1][k];//没有空间
                else
                    dp[i][k] = max(dp[i-1][k],dp[i-1][k-w[i]]+v[i]);
                max_all=max(max_all,dp[i][k]);
            }    
        }
    }    
    cout<<max_all<<endl;
    return 0;
1183 编辑距离技术分享
基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题
技术分享 收藏
技术分享 关注
编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
例如将kitten一字转成sitting:
sitten (k->s)
sittin (e->i)
sitting (->g)
所以kitten和sitting的编辑距离是3。俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。
给出两个字符串a,b,求a和b的编辑距离。
 
Input
第1行:字符串a(a的长度 <= 1000)。
第2行:字符串b(b的长度 <= 1000)。
Output
输出a和b的编辑距离
Input示例
kitten
sitting
Output
3
在这里删除元素和插入的效果相同可以不用考虑,只考虑替换和插入dp[i][j]表示由a的前i个字符转换到b的前j个字符所需要的步数,插入是
dp[i][j] = max(dp[i-1][j],dp[i][j-1])+1,
替换是,dp[i][j] = dp[i-1][j-1],当a[i]==b[j] 不必操作 dp[i][j]=dp[i-1][j-1]
可得
dp[i][j] = max(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+a[i]==b[j]?0:1)

51nod 简单的动态规划