Uva 12563 - Jin Ge Jin Qu(01背包)
题目链接 https://cn.vjudge.net/problem/UVA-12563
【题意】
KTV有规定,当时间到的时候不会把正在唱的歌切掉,而是会等它放完。现在有一首时长为678秒的劲歌金曲,假设你在唱KTV,还有t秒时间,接下来你要唱n首歌(不含劲歌金曲),然后在时间结束之前再唱一首劲歌金曲,使得唱歌总曲目最多的情况下,你离开KTV的时间尽量晚。
【输入格式】
输入整数T,共有T组输入数据,每组输入n(n <= 50),t(t <= 1e9)和每首歌的长度(不超过3分钟)。保证这n+1首歌的总长大于t。
【输出格式】
输出数据组数,唱的总曲目数和时间总长度。
【思路】
01背包问题的变型,抽象成背包问题,背包的总重为t-1,因为至少要留下1秒来唱最后的劲歌金曲。首先一首歌对应一件物品,物品的权值和重量都是输入中每首歌的时间,然后约束条件有两个,首先要满足尽可能地将更多的物品加入到背包中,其次要满足物品的价值尽量大。注意数据范围,虽然t<=1e9,但是因为保证n+1首曲子的时间大于t,所以t<180n+678
#include<bits/stdc++.h>
using namespace std;
const int maxn=15000;
int n,w;
int v[maxn];
struct node{
int p,c;
node(int pp=0,int cc=0):p(pp),c(cc){}
}dp[maxn];
int main(){
cin.tie(0);
ios_base::sync_with_stdio(0);
int T;
cin>>T;
for(int kase=1;kase<=T;++kase){
cin>>n>>w;
for(int i=0;i<w;++i) dp[i]=node(0,0);
for(int i=0;i<n;++i) cin>>v[i];
for(int i=0;i<n;++i){
for(int j=w-1;j>=v[i];--j){
if(dp[j].c<dp[j-v[i]].c+1){
dp[j].c=dp[j-v[i]].c+1;
dp[j].p=dp[j-v[i]].p+v[i];
}
else if(dp[j].c==dp[j-v[i]].c+1 && dp[j].p<dp[j-v[i]].p+v[i]){
dp[j].p=dp[j-v[i]].p+v[i];
}
}
}
printf("Case %d: %d %d\n",kase,dp[w-1].c+1,dp[w-1].p+678);
}
return 0;
}