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

来源:互联网 发布:怎么理解面向对象编程 编辑:程序博客网 时间:2024/06/06 21:03

点击打开链接

 其实本题本质上就是一个标准的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);            }        } 

或者利用滚动数组,因为只有一行,所以直接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;   }