查看: 1152|回復: 0
打印 上一主題 下一主題

[ZJ] b135 - NOIP2006 2.金明的预算方案

[複製鏈接]
  • TA的每日心情
    慵懶
    2015-4-10 14:18
  • 簽到天數: 78 天

    [LV.6]常住居民II

    176

    主題

    612

    帖子

    3959

    積分

    管理員

    Rank: 9Rank: 9Rank: 9

    積分
    3959

    台南一中資訊社新手達陣程式設計達人 - 2014

    跳轉到指定樓層
    樓主
    發表於 2014-8-18 11:33:36 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式

    趕快加入我們來參與討論吧!

    您需要 登錄 才可以下載或查看,沒有帳號?加入我們

    x
    原題:http://zerojudge.tw/ShowProblem?problemid=b135
    題解:01背包問題、有限制條件、DP

    內容:
    跟一班01背包問題的不同點,在於有一些物品分成主要的跟附加的。若要拿取附加的物品,則其主要物品必須拿取。主要物品不會是主要物品另一附加物品。

    解題方法:
    令DP[n][W][p],其中n必須為主商品的編號,代表考慮完n號主商品及其附加商品,花費洽W下,價值和的最大值。其中p=0代表不拿主商品,p=1則為拿主商品。

    轉移方法先考慮主商品的部分,p=0很簡單就不多提,那p=1時,若當前狀態W不足以支付主商品,則令值等於0。然後再考慮該主商品之附加商品,轉移時小心當前狀態及轉移狀態DP[n][W][1]都不能為0,才能滿足題目要求的「若要拿取附加的物品,則其主要物品必須拿取」。

    此外該作法有跳編號的狀況(雖然可以避免XD),故用額外的變數pn,pl,代表當前與前一個主商品的編號。

    小技巧:由於題目保證價錢都是10的倍數,可以先除掉,輸出時再乘回來就好。


    [C++] 純文本查看 復制代碼
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #include<iostream>
    using namespace std;
    
    struct item{
            int v;
            int p;
            int w;
    };
    
    item obj[61];
    vector<item> part[61];
    
    int dp[61][3200][2];
    
    int main()
    {
            int V,N,pn,pl;
            while(~scanf("%d%d",&V,&N))
            {
                    V/=10;
                    for(int i=1;i<=N;++i)
                            part[i].clear();
                    for(int i=1;i<=N;++i)
                    {
                            scanf("%d%d%d",&obj[i].v,&obj[i].p,&obj[i].w);
                            obj[i].v/=10;
                            if(obj[i].w)
                                    part[obj[i].w].push_back(obj[i]);
                    }
            
                    memset(dp,0,sizeof(dp));
                    pn=pl=0;
                    for(int i=1;i<=N;++i)
                    {
                            if(obj[i].w)
                                    continue;
                            pl=pn;
                            pn=i;
                            for(int j=0;j<=V;++j)
                            {
                                    dp[pn][j][0]=max(dp[pl][j][0],dp[pl][j][1]);
                                    if( j-obj[i].v < 0 )
                                            dp[pn][j][1]=0;
                                    else
                                            dp[pn][j][1]=obj[i].v*obj[i].p+max(dp[pl][j-obj[i].v][0],dp[pl][j-obj[i].v][1]);
                            }
    
                            for(int k=0 ; k<part[i].size() ; ++k)
                            {
                                    item &t=part[i][k];
                                    for( int j=V; j>=t.v ;--j )
                                    {
                                            if( dp[pn][j-t.v][1] && dp[pn][j][1] )
                                                    dp[pn][j][1] = max( dp[pn][j][1] , dp[pn][j-t.v][1]+t.v*t.p ); 
                                    }
                            }
                    }
                    int ans=0;
                    for(int i=0;i<=V;++i)
                    {
                            ans =max(ans ,dp[pn][i][0] ); 
                            ans =max(ans ,dp[pn][i][1] ); 
                    }
                    printf("%d\n",ans*10);
            }
    }



    回復

    使用道具 檢舉

    您需要登錄後才可以回帖 登入 | 加入我們

    本版積分規則

    快速回覆 返回頂部 返回列表