acm DP经典5题

1.最大连续子序列

给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。最大连续子序列是所有连续子序中元素和最大的一个, 例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20。

状态转移方程:dp[i]=max(dp[i-1]+a[i],a[i]);



#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<algorithm>
#include <map>
#include <set>
using namespace std;
//2015.4.1

//最大连续子序列  假设100个数

typedef long long LL;
int dp[100];
int a[100];
int n;
int main()
{
    while(true)
    {
        memset(dp,0,sizeof(dp));
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        dp[1]=a[1];
        for(int i=2;i<=n;i++)
        {
            dp[i]=max(dp[i-1]+a[i],a[i]);
        }
        printf("%d\n",dp[n]);


    }
    return 0;
}

2.数塔问题

acm DP经典5题_第1张图片

数塔问题 :要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?


状态转移方程:dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<algorithm>
#include <map>
#include <set>
using namespace std;
//2015.4.1


//数塔
typedef long long LL;
int n;
int dp[100][100];
int a[100][100];
int main()
{
    while(true)
    {
        cin>>n;
        int key=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                cin>>a[i][j];
                if(i==n)
                {
                    dp[i][j]=a[i][j];
                }
            }
            for(int i=n-1;i>=1;i--)
            {
                for(int j=1;j<=i;j++)
                {
                    dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];
                }
            }
        }
        cout<<dp[1][1]<<endl;
    }
    return 0;
}

3.背包问题


N 件物品和一个容量为 V 的背包。第 i 件物品的费用是 c[i] ,价值是 w[i] 。求解将哪些物品装入背包可使价值总和最大。


状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+c[i]);

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<algorithm>
#include <map>
#include <set>
using namespace std;
//2015.4.1

//背包问题
int c[100],w[100];
int dp[100][100];//前i个物品中选j重
int n,v;
int main()
{
    while(true)
    {
        memset(dp,0,sizeof(dp));
        cin>>n>>v;
        for(int i=1;i<=n;i++)
        {
            cin>>c[i]>>w[i];
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=v;j++)
            {
                dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+c[i]);
            }
        }
        cout<<dp[n][v]<<endl;
    }
    return 0;
}

4.最长递增子序列

给定一个序列  An  a1 ,a2 ,  ... , an  ,找出最长的子序列使得对所有  j  , ai  aj 

状态转移方程:i>j   if(a[i]>a[j]) dp[i]=dp[j]+1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<algorithm>
#include <map>
#include <set>
using namespace std;
//2015.4.1



//最长递增子序列

int f[100];
int a[100];
int n;
int ans;
int main()
{
    while(true)
    {
        cin>>n;
        ans=1;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            f[i]=1;
        }
        for(int i=2;i<=n;i++)
        {
            for(int j=i-1;j>=1;j--)
            {
                if(a[i]>a[j]&&f[i]<=f[j])
                {
                    f[i]=f[j]+1;
                    if(f[i]>ans)ans=f[i];
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}


5.最长公共子序列

一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。

这个题似乎常用来检测是否一篇文章时抄袭的。

状态转移方程:if(a[i]==b[j])dp[i][j]=dp[i-1][j-1]+1
else if(a[i]!=a[j]) dp[i][j]=dp[i-1][j-1]
      if(i==0||j==0)dp[i][j]=0

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<algorithm>
#include <map>
#include <set>
using namespace std;
//2015.4.1

//最长公共子序列
int dp[100][100];
int a[100];
int b[100];
int n,m;
int main()
{
    while(true)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            dp[i][0]=0;
        }
        for(int j=1;j<=m;j++)
        {
            cin>>b[j];
            dp[0][j]=0;
        }
        dp[0][0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(a[i]==b[j])
                {
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                else if(dp[i][j-1]>=dp[i-1][j])
                {
                    dp[i][j]=dp[i][j-1];
                }
                else
                {
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        cout<<dp[n][m]<<endl;

    }
    return 0;
}



你可能感兴趣的:(dp,ACM)