寧波工程學院2020新生校賽 E 皮卡丘這麼可愛,當然要.....(多重揹包二進制優化裸題)

題目鏈接

題目描述
訓練師小梁在一次機緣巧合中,發現了一個皮卡丘部落,她非常喜歡皮卡丘,但由於精靈球有限,所以她打算在這裏逗留一段時間,部落中有\text{n}n個皮卡丘,每個皮卡丘有不同的可愛度qi ,小梁要欣賞這些皮卡丘,但有的皮卡丘被看多了會抑鬱,所以她要合理的分配時間和看的次數,收穫最多的可愛度。
輸入描述:
到達部落的時間e, s(24小時制時間),皮卡丘的個數n(s≤e,n≤10 5 )下面n行t,q,s分別代表:欣賞這隻皮卡丘需要的時間(分鐘),這隻皮卡丘的可愛度,這隻皮卡丘最多能看幾次(s=0表示這隻皮卡丘脾氣很好,能看無限次)
輸出描述:
一個整數,表示能獲取的最大可愛度
示例1
輸入

5:30 7:10 5
3 1 5
4 4 2
2 1 0
4 5 3
5 6 0

輸出

120

題目中把n個皮卡丘理解爲n種物品,需要的時間理解爲體積,獲得的可愛度理解爲價值,在加上有限定次數,可以顯而易見的看出這道題是一道多重揹包,再看題面中的數據範圍n爲10000,n^3的多重揹包寫法必定會超時,這就要用到了二進制優化。

二進制優化基於數論的一個知識,任意的一個整數中的任意的一個數,都可以由所有不大於這個整數的的

2^n的數組合而成,例如18=1+2+4+8+3, 18中的任意數都可以由1,2,4,8,3組合而成。

當p[i]=0時說明可以無限拿,可以直接轉換成完全揹包。

其中關於開始時間和結束時間轉換成時間段大小有多種方法(這裏列出兩種,模擬或scanf的格式讀入)

我們定義狀態dp[s]表示當時間段大小爲s時,能獲得的最大可愛度。

狀態轉移方程爲

dp[j]=max(dp[j],dp[j−t[i]]+c[i])
dp[k]=max(dp[k],dp[k−j∗t[i]]+j∗c[i])


我寫的2進制優化程序只能過80%,原因不知道。

#include<bits/stdc++.h>
#include<bitset>
#include<unordered_map>
#define pb push_back
#define bp __builtin_popcount
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e6+100;
const int MOD=1e9+7;
int lowbit(int x){return x&-x;}
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }
int n,m,x1,x2,y11,y22,t,q,s;
ll dp[maxn];
struct node{
    int x,y;
};
vector<node>G;
int main()
{
 
     scanf("%d:%d%d:%d%d",&x1,&y11,&x2,&y22,&n);
     m=(x2-x1)*60+y22-y11;
     for(int i=1;i<=n;i++)
     {
       scanf("%d%d%d",&t,&q,&s);//一次消耗的時間 一次獲得的可愛度  次數
        if(s==0||s>m/t)s=m/t;
        for(int c=1;c<=s;c<<1)
        {
          G.push_back(node{t*c,q*c});
          s-=c;
        }
        if(s)G.push_back(node{t*s,q*s});
  
     }
  
     for(auto it:G)
     for(int j=m;j>=it.x;j--)
     {
        dp[j]=max(dp[j],dp[j-it.x]+it.y);
     }
     cout<<dp[m]<<endl;
  
     system("pause");
     return 0;
  
  
}

可能是因爲vector儲存方式比較慢導致的。

AC代碼如下

#include<cstdio>
int n,m,s,f[10000],a[1100005],b[1100005],x1,y1,x2,y2,w,v,k,x;
inline int max(int a,int b){return a>b?a:b;}
int main()
{
    scanf("%d:%d%d:%d%d",&x1,&y1,&x2,&y2,&n);
    s=(x2-x1)*60+y2-y1;
    for(int i=0;i<n;++i)
      {
        scanf("%d%d%d",&w,&v,&k);
        if(k==0||k>s/w)k=s/w;
        for(x=1;x<=k;x<<=1)a[++m]=x*w,b[m]=x*v,k-=x;
        if(k)a[++m]=k*w,b[m]=k*v;
         
      }
    for(int i=1;i<=m;++i)
      {
        for(int j=s;j>=a[i];--j)
          f[j]=max(f[j-a[i]]+b[i],f[j]);
      }
    printf("%d",f[s]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章