【习题】动态规划!

本文中的习题来自 Loi_DQS dalao整理的DP学习资料

1.【codevs1220】数字三角形问题

记忆化搜索:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int sz=1000+50;
 5 int map[sz][sz],dp[sz][sz];
 6 int n;
 7 int dfs(int i,int j)
 8 {
 9     if(i==n) return map[i][j];
10     if(dp[i+1][j]==0) dp[i+1][j]=dfs(i+1,j);
11     if(dp[i+1][j+1]==0) dp[i+1][j+1]=dfs(i+1,j+1);
12     return dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+map[i][j];
13 }
14 int main()
15 {
16     scanf("%d",&n);
17     for(int i=1;i<=n;i++)
18         for(int j=1;j<=i;j++)
19             scanf("%d",&map[i][j]);
20     printf("%d",dfs(1,1));
21     return 0;
22 }
View Code

顺推:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int sz=1000+50;
 6 int map[sz][sz],dp[sz][sz];
 7 int main()
 8 {
 9     int n;
10     scanf("%d",&n);
11     for(int i=1;i<=n;i++)
12         for(int j=1;j<=i;j++)
13             scanf("%d",&map[i][j]);
14     for(int i=1;i<=n;i++)
15         for(int j=1;j<=i;j++)
16             dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+map[i][j];
17     int ans=-999;
18     for(int i=1;i<=n;i++)
19         ans=max(ans,dp[n][i]);
20     printf("%d",ans);
21     return 0;
22 }
View Code

逆推:

#include<cstdio>
#include<algorithm>
using namespace std;
const int sz=1000+50;
int map[sz][sz],dp[sz][sz];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            scanf("%d",&map[i][j]);
    for(int i=n;i>=0;i--)
        for(int j=1;j<=i;j++)
            dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+map[i][j];
    printf("%d",dp[1][1]);
    return 0;
}
View Code

2.【codevs1576】最长上升子序列(LIS)问题

常规做法

#include<cstdio>
#include<algorithm>
using namespace std;
const int sz=5000+50;
int num[sz],dp[sz];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&num[i]);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        dp[i]=1;//初始化 以i结尾的LIS长度最小为1 
        for(int j=1;j<i;j++)
            if(num[j]<num[i])
                dp[i]=max(dp[i],dp[j]+1);
        ans=max(ans,dp[i]);
    }
    printf("%d",ans);
    return 0;
}
View Code

O(nlogn)做法。。。

3.方格取数问题

#include<cstdio>
#include<algorithm>
using namespace std;
const int sz=5000+50;
int map[sz][sz],dp[sz][sz];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&map[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            dp[i][j]=max(dp[i-1][j],dp[i][j-1])+map[i][j];
        }
    printf("%d",dp[n][m]);
    return 0;
}
View Code

4.【codevs1102】01背包问题

常规做法

#include<cstdio>
#include<algorithm>
using namespace std;
const int sz=1000+100;
struct node{
    int tim,val;
}th[sz];
int dp[sz][sz];
int main()
{
    int t,m;
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&th[i].tim,&th[i].val);
    for(int i=1;i<=m;i++)
        for(int j=0;j<=t;j++)
        {
            if(j>=th[i].tim)
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-th[i].tim]+th[i].val);
            else dp[i][j]=dp[i-1][j];
        }
            
    printf("%d",dp[m][t]);
    return 0;
}
View Code

滚动数组

#include<cstdio>
#include<algorithm>
using namespace std;
const int sz=1000+10;
struct node{
    int tim,val;
}th[sz];
int dp[sz];
int main()
{
    int t,m;
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++)
    {
        int tim,val;
        scanf("%d%d",&tim,&val);
        th[i].tim=tim,th[i].val=val;
    }
    for(int i=1;i<=m;i++)
        for(int j=t;j>=th[i].tim;j--)
        {
            dp[j]=max(dp[j],dp[j-th[i].tim]+th[i].val);
        }
    printf("%d",dp[t]);
    return 0;
}
View Code

 5.【luogu1616】完全背包问题

滚动数组

#include<cstdio>
#include<algorithm>
using namespace std;
const int sz=100000+10;
int c[sz/10],v[sz/10],dp[sz];
int main()
{
    int t,m;
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&c[i],&v[i]);
    for(int i=1;i<=m;i++)
        for(int j=c[i];j<=t;j++)
            dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
    printf("%d",dp[t]);
    return 0;
}
View Code

 6.最长公共子序列

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int sz=3000+10;
ll a[sz],b[sz];
int dp[sz][sz];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        dp[i][0]=0;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&b[i]);
        dp[0][i]=0;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if(a[i]==b[j])
                dp[i][j]=max(dp[i-1][j-1]+1,max(dp[i][j-1],dp[i-1][j]));
            else 
                dp[i][j]=max(dp[i-1][j-1],max(dp[i][j-1],dp[i-1][j]));
        }
    printf("%d",dp[n][n]);
    return 0;
    
}
View Code

7.区间DP 【codevs1048】石子归并问题

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int sz=100+10;
int a[sz],dp[sz][sz],sum[sz];
int main()
{
    int n;
    scanf("%d",&n);
    memset(dp,63,sizeof(dp));//求最大值,先初始化 
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
        dp[i][i]=0;//边界条件 
    }
    for(int i=n;i>0;i--)
        for(int j=i+1;j<=n;j++)
            for(int k=i;k<j;k++)
                    dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
    printf("%d",dp[1][n]);
    return 0;
}
View Code

 8.【codevs2152】滑雪

#include<cstdio>
#include<algorithm>
using namespace std;
const int sz=100+10;
int map[sz][sz],dp[sz][sz];
int dx[5]={0,0,1,0,-1};
int dy[5]={0,1,0,-1,0};
int r,c;
int dfs(int i,int j)
{
    if(dp[i][j]) return dp[i][j];
    int ans=1;
    for(int k=1;k<=4;k++)
            {
                int x=i+dx[k],y=j+dy[k];
                if(x>0&&x<=r&&y>0&&y<=c&&map[i][j]>map[x][y])
                    ans=max(ans,dfs(x,y)+1);        
            }
    return dp[i][j]=ans;
}
int main()
{
    scanf("%d%d",&r,&c);
    for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++)
            scanf("%d",&map[i][j]);
    int ans=0;
    for(int i=1;i<=r;i++)
        for(int j=1;j<=c;j++)
            ans=max(ans,dfs(i,j));
    printf("%d",ans);
    return 0;    
}
View Code

9.

10.【codevs1044】拦截导弹

O(n^2)做法:

#include<cstdio>
#include<algorithm>
using namespace std;
const int sz=100000+10;
int a[sz],dp1[sz],dp2[sz],tot;
int main()
{
    while(scanf("%d",&a[++tot])!=EOF);
    int ans=0;
    for(int i=1;i<tot;i++)
    {
        dp1[i]=1;
        for(int j=1;j<i;j++)
        {
            if(a[j]>=a[i])
                dp1[i]=max(dp1[i],dp1[j]+1);
        }
        ans=max(ans,dp1[i]);
    }
    printf("%d\n",ans);
    ans=0;
    for(int i=1;i<tot;i++)
    {
        dp2[i]=1;
        for(int j=1;j<i;j++)
        {
            if(a[j]<a[i])
                dp2[i]=max(dp2[i],dp2[j]+1);    
        }
        ans=max(ans,dp2[i]);
    }
    printf("%d",ans);
    return 0;
}
        
View Code

O(nlogn)做法:

 

posted @ 2018-01-09 21:55  dprswdr  阅读(166)  评论(0)    收藏  举报