題目描述
訓練師小梁在一次機緣巧合中,發現了一個皮卡丘部落,她非常喜歡皮卡丘,但由於精靈球有限,所以她打算在這裏逗留一段時間,部落中有\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]);
}