Jin Ge Jin Qu hao (01背包学习 紫薯)

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/Draven__/article/details/77504576

点击打开链接

 其实本题本质上就是一个标准的01背包问题. 问你<=t-1时间内最多可以选择哪些歌曲使得 (数据1,数据2) 最优. 这里的数据1是歌曲数目, 数据2是歌曲总时长, 且数据1优先.

我们令dp[i][j]==x 表示当决策完全前i个物品后(选或不选), 所选的总歌曲时长<=j时, 所得到的最优状态为x. (这里的x就不是平时我们所说的最长时间或最多歌曲数目了)

但是如果用二维数组实现的话,d数组是从上到下,从右往左计算的

        sort(v+1,v+n+1);
        t--;
        memset(d,-1,sizeof(d));
        d[0][0]=0;
        for(int i=1; i<=n; i++)
        {
            d[i][0]=0;
            for(int j=t; j>=v[i]; j--)
            {
                d[i][j]=max(d[i-1][j],d[i-1][j-v[i]]+1);
            }
        }
        //cout<<d[1][133]<<endl;  0
        //cout<<d[2][133]<<endl;  1
        //cout<<d[3][133]<<endl; -1
        //cout<<d[4][133]<<endl; -1

这样就会导致一个问题,例如t=145 v[1]=19,v[2]=133,v[3]=167,v[4]=168,这样计算之后d[2][133]为1,d[3][133]反而成了-1,因为v[3]=167>145 所以第二层循环根本没跑,d[3][133]依旧等于-1

如果改成这样,就没问题了

  	sort(v+1,v+n+1);
        t--;
        memset(d,-1,sizeof(d));
        d[0][0]=0;
        for(int i=1; i<=n; i++)
        {
            d[i][0]=0;
            for(int j=t; j>=0; j--)
            {
                d[i][j]=d[i-1][j];  //让第i层等于第i-1层
                if(j>=v[i])d[i][j]=max(d[i-1][j],d[i-1][j-v[i]]+1);
            }
        } 	sort(v+1,v+n+1);
        t--;
        memset(d,-1,sizeof(d));
        d[0][0]=0;
        for(int i=1; i<=n; i++)
        {
            d[i][0]=0;
            for(int j=t; j>=0; j--)
            {
                d[i][j]=d[i-1][j];  //让第i层等于第i-1层
                if(j>=v[i])d[i][j]=max(d[i-1][j],d[i-1][j-v[i]]+1);
            }
        } 

或者利用滚动数组,因为只有一行,所以直接d[i][j]=d[i-1][j]了,不用赋值

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
LL mod=1e9+7;
const int N=1005;

int n,t;
int d[10005]; //在j时间下的最大歌数
int v[55];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    //int kase=0;
    int T;
    cin>>T;
    int kase=0;
    while(T--)
    {
        cin>>n>>t;
        for(int i=1;i<=n;i++)
            cin>>v[i];

        sort(v+1,v+n+1);
        t--;
        memset(d,-1,sizeof(d));
        d[0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=t;j>=v[i];j--)
            {
                d[j]=max(d[j],d[j-v[i]]+1);
            }
        }
        /*for(int i=1;i<=n;i++)
        {
            for(int j=v[i];j<=t;j++)
            {
                cout<<d[i][j];
            }
            cout<<endl;
        }*/
        int ans=t;
        for(int i=t;i>=0;i--)
        {
            if(d[i] > d[ans])
            {
                ans=i;
            }
        }
        cout<<"Case "<<++kase<<": "<<d[ans]+1<<" "<<ans+678<<endl;
    }
}

或者直接用两个dp

#include<stdio.h>  
#include<string.h>  
int max(int x,int y){  
 if(x>=y) return x;  
 else return y;  
}  
int d[55][10000];  
int len[55][10000];  
int main(){  
 int tag,m,n,t,time[55];  
 scanf("%d",&m);  
 int count=1;  
 while(count<=m){  
  memset(d,0,sizeof(d));  
  memset(len,0,sizeof(len));  
  scanf("%d%d",&n,&t);  
  for(int i=1;i<=n;i++) scanf("%d",&time[i]);  
  for(int i=n;i>=1;i--){  
   for(int j=1;j<=t;j++){  
    d[i][j]=d[i+1][j];  
    len[i][j]=len[i+1][j];  
    if(j>time[i]) {  
     if(d[i][j]<d[i+1][j-time[i]]+1){  
      d[i][j]=d[i+1][j-time[i]]+1;  
      len[i][j]=len[i+1][j-time[i]]+time[i];  
     }  
     else if(d[i][j]==d[i+1][j-time[i]]+1) len[i][j]=max(len[i][j],len[i+1][j-time[i]]+time[i]);  
    }  
   }  
  }  
  printf("Case %d: %d %d\n",count,d[1][t]+1,len[1][t]+678);  
  count++;  
 }  
 return 0;   
}  


 

猜你喜欢

转载自blog.csdn.net/Draven__/article/details/77504576