首页 > 代码库 > 动态规划练习题

动态规划练习题

RQNOJ 496

/*
  dp记录路径的问题
  f[i][j]表示用前j个花瓶盛放前i朵花的最大值
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#define N 110
#define INF 1000000000
using namespace std;
int a[N][N],f[N][N],q[N],n,m;
int main()
{
    memset(f,-127/3,sizeof(f));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
        scanf("%d",&a[i][j]);
    f[0][0]=0;
    for(int i=1;i<=n;i++)
      for(int j=i;j<=m;j++)
        for(int k=i-1;k<j;k++)
          f[i][j]=max(f[i-1][k]+a[i][j],f[i][j]);
    int ans=-INF,pos;
    for(int i=n;i<=m;i++)
      if(f[n][i]>ans)
      {
          ans=f[n][i];pos=i;
      }
    printf("%d\n",ans);
    q[n]=pos;
    int x=n;
    while(x--)
    {
        for(int i=1;i<pos;i++)
          if(f[x][i]==ans-a[x+1][pos])
          {
              q[x]=i;ans-=a[x+1][pos];pos=i;
              break;
          }
    }
    for(int i=1;i<=n;i++)printf("%d ",q[i]);
    return 0;
}

tyvj 1313

/*
  朴素的动规很好想,f[i]表示选前i个且第i个必选的最小值。f[i]=f[j]+a[i]
  因为可以选的j来自一段固定长度的区间,并且我们每次要选最小值,所以可以用单调队列优化。
*/
#include<iostream>  
#include<cstring>  
#include<cstdio>  
#define N 1000010
#define inf 2100000000   
using namespace std;  
int n,m,head,tail,Min;  
int q[N],a[N],f[N];  
int main()
{  
    scanf("%d%d",&n,&m);  
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);  
    for (int i=1;i<=n;i++)
    {  
        while (q[head]<i-m&&head<=tail) head++;  
        f[i]=a[i]+f[q[head]];  
        while (f[q[tail]]>f[i]&&head<=tail) tail--;  
        q[++tail]=i;  
    }  
    Min=inf;  
    for (int i=n-m+1;i<=n;++i)  
      Min=min(Min,f[i]);  
    printf("%d\n",Min);  
}

洛谷 1650

/*
  虽说是dp,但总觉得有些贪心的思想在里面
  因为我们尽量要把齐王的跑得慢的马比下去,而且要尽量用田忌的马中比较慢的。
  所以先排一遍序,然后当当前田忌的马慢时,换下一匹,如果一样快,可以换下一匹,也可以这样比,如果快,就比。
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 2016
#define inf 100000000
using namespace std;
int a[N],b[N],f[N][N],n,ans=-inf;
int dfs(int x,int y)
{
    if(f[x][y]!=-1)return f[x][y];
    if(x>n)return 0;
    if(a[x]<b[y])f[x][y]=dfs(x+1,y)-200;
    else if(a[x]==b[y])
      f[x][y]=max(dfs(x+1,y)-200,dfs(x+1,y+1));
    else f[x][y]=dfs(x+1,y+1)+200;
    return f[x][y];
}
int main()
{
    freopen("jh.in","r",stdin);
    memset(f,-1,sizeof(f));
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
      scanf("%d",&b[i]);
    sort(a+1,a+n+1);sort(b+1,b+n+1);
    printf("%d",dfs(1,1));
    return 0;
}

洛谷 1594

/*
  80分,有两个数据爆了double了,没有过
  记忆化搜索,很好理解。 
  f[x][y]表示通过前x辆车,且第x辆车所属车队以y开头的最少时间 
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#define N 1010
using namespace std;
int w[N],n,zz;double f[N][N],t[N],s,ans=100000000.0;
double query(int x,int y)//数据较弱,懒得写rmq了 
{
    double maxn=0;
    for(int i=x;i<=y;i++)
      maxn=max(maxn,t[i]);
    return maxn;
}
double dfs(int x,int y)
{
    if(f[x][y]!=-1.0)return f[x][y];
    if(x>n)return 0;
    if(w[x+1]-w[y-1]<=zz&&x<n)
      f[x][y]=min(dfs(x+1,y),dfs(x+1,x+1)+query(y,x));
    else
      f[x][y]=dfs(x+1,x+1)+query(y,x);
    return f[x][y];
}
int main()
{
    scanf("%d%lf%d",&zz,&s,&n);
    for(int i=0;i<=n;i++)
      for(int j=0;j<=n;j++)
        f[i][j]=-1.0;
    for(int i=1;i<=n;i++)
    {
        double v;scanf("%d%lf",&w[i],&v);
        t[i]=s*60/v;w[i]+=w[i-1];
    }
    printf("%.1lf",dfs(1,1));
    return 0;
}

 

动态规划练习题