您的位置:首页 > 其它

UVA-624 CD (DP)

2016-04-18 22:26 405 查看
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=565



题目大意:一张CD上有不超过20首歌,选取时间和不超过n分钟的歌曲,要求时间和最大,最后按原顺序输出每首歌曲的时间,及时间和。

依旧是一个01背包,不过需要输出路径(题目没说明时间和相同时该怎么办,看了样例认为是选取歌曲最多的),按升序排序后,状态转移是先达到的,但由于从时间短的歌曲开始转移,所以转移到的第一个一定是歌曲最多的(AC后看到别人谈到这题是Special Judge...)

最初用dp[i]记录时间和i是否能够凑成,cur[i]表示时间和为i时选的最后一个歌的下标,AC之后又想到可以将dp数组与cur数组合并,减少空间浪费

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct Track {
int minu,index;

bool operator < (const Track& a) const {
return minu<a.minu;
}
}tra[25],path[25];

int n,m,dp[2005],ans,cnt,tmp;//dp[i]表示时间和为i时选的最后一个歌的下标,dp[i]=-1表示目前无法凑成为i时间和

bool cmp(const Track& a,const Track& b) {
return a.index>b.index;
}

int main() {
while(scanf("%d%d",&n,&m)==2) {
memset(dp,-1,sizeof(dp));
dp[0]=0;
ans=0;
for(int i=0;i<m;++i) {
scanf("%d",&tra[i].minu);
tra[i].index=i;
}
sort(tra,tra+m);//按时间升序排序
for(int i=0;i<m;++i) {
for(int j=n;j>=tra[i].minu;--j) {
if(dp[j-tra[i].minu]!=-1&&dp[j]==-1) {//如果dp[j-tra[i].minu]能凑成,且dp[j]不能凑成
dp[j]=i;
ans=max(ans,j);
}
}
}
tmp=ans;
cnt=0;
while(tmp!=0) {
path[cnt++]=tra[dp[tmp]];
tmp-=tra[dp[tmp]].minu;
}
sort(path,path+cnt,cmp);//路径按下标升序排序
while(--cnt>=0)
printf("%d ",path[cnt].minu);
printf("sum:%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: