UVA 12563 Jin Ge Jin Qu hao(01揹包|經典動態規劃)

題目鏈接

題意

可以參見紫書P274
1. n首歌,在t-1秒內唱完
2. 唱完之後唱678s的金曲,這樣就能使唱的時間最長
3. 我們要先保證唱的總曲目最多,當曲目相同的時候保證總時長最長

解決


  1. 經典的01揹包問題
  2. 考慮到狀態比較複雜,有曲目,有時長.我們把狀態用一個結構體來表示
  3. 這裏參考了下博客,用了滾動數組
  4. 要注意一下,如果前n首的總時長<=t-1,那麼這n首歌都可以唱
  5. 注意一下我們最終的狀態是t-1的狀態而不是t的狀態

我也是算法新手,對於滾動數組我是這麼理解的
1. 我們遍歷每首歌在一些情況下的最優解(也就是最外層的for(i) )
2. 可以看一下紫書的滾動數組的講解,我能力還不足以講清
3. 我還是再想想吧^_^,我會補充的!

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int t[52];
struct node
{
    int num,time;
    bool operator>(const node &n2)const
    {
        if(num==n2.num) return time>n2.time;
        return num>n2.num;
    }
}dp[180*52];
int main()
{
    int c=1,sum_t,cases;
    scanf("%d",&cases);
    while(cases--)
    {
        printf("Case %d: ",c++);
        int n,max_t;
        scanf("%d%d",&n,&max_t);

        sum_t=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&t[i]);
            sum_t+=t[i];
        }

        if(sum_t<=max_t-1)
        {
            printf("%d %d\n",n+1,sum_t+678);
            continue;
        }

        max_t--;            //選的歌曲總時長應<=max_t-1而不是max_t(這樣就沒法唱金曲了)
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        {
            for(int j=max_t;j>=t[i];j--)        //滾動數組中j只能從後往前掃
            {
                node tmp;
                tmp.num=dp[j-t[i]].num+1;       //狀態轉移
                tmp.time=dp[j-t[i]].time+t[i];  //狀態轉移

                if(tmp>dp[j]) dp[j]=tmp;        //類似於01揹包問題中,能放下的情況
            }
        }
        printf("%d %d\n",dp[max_t].num+1,dp[max_t].time+678);
    }
}
發佈了54 篇原創文章 · 獲贊 8 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章