您的位置:首页 > 其它

百度之星资格赛1004 01背包+记录路径套路

2017-08-15 01:36 337 查看
题目链接

/*
百度之星资格赛1004
01背包套路题.这个题目是一个01背包+记录路径的题目.
关于记录路径的套路题,一般开一个book标记一下,book[i][j]表示容量为j时放入了第i个物品.
由于我们从前往后将物品装入背包并维护最大值,所以我们看背包中装入哪些物品时从后往前,
因为前面的物品已经有一个价值了,如果后面的物品能放进去那么一定是使答案变得更优了,那么我们就
从后往前遍历放入的物品,然后将它的价值减去一直往前,直到价值变为0.
但是这个题目是存在价值为0的东西的,是一个坑点.!!!!
判断字典序最小的时候,我就是直接把所有放进的物品取出来,排个序然后比较字典序就好

*/

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
const int maxn = 1e3+10;
int m,n;
ll s[maxn],c[maxn],dp[maxn];
int book[maxn][maxn];
int num[maxn][maxn];
int cmp(int x,int y)
{
for(int i=1,j=1;i<=num[x][0]&&j<=num[y][0];i++,j++)
{
if(num[x][i]!=num[y][j])
return num[x][i]-num[y][j];
}
return 0;
}
int main()
{
int t;
cin>>t;
int ca =1;
while(t--)
{
memset(dp,0,sizeof (dp));
memset(book,0,sizeof (book));
memset(num,0,sizeof (book));
scanf("%d%d",&m,&n);
for(int i = 1;i <= n;i++)
scanf("%lld%lld",&s[i],&c[i]);
for(int i=1;i<=n;i++)
{
for(int j=m;j>=c[i];j--)
{
if(dp[j]<dp[j-c[i]]+s[i])
{
dp[j]=dp[j-c[i]]+s[i];
book[i][j]=1;
}
}
}
ll index=inf;
ll maxx=0;
int cnt=0,item=0;
for(int i=0;i<=m;i++)
maxx=max(dp[i],maxx);
for(int i=m;i>=0;i--)
{
if(dp[i]==maxx)
{
ll sum=0;
int k=1;
int j=n,w=i;
while(j>=1&&w>=0)
{
if(book[j][w])
{
num[cnt][k++]=j;
sum+=j;
w-=c[j];
}
j--;
}
num[cnt][0]=k-1;
sort(num[cnt]+1,num[cnt]+1+num[cnt][0]);
if(index>sum)
{
index=sum;
item=cnt;
}
else if(index==sum&&cmp(item,cnt)>0)
{
item=cnt;
}
cnt++;
}
}
ll money=0,score=0;
for(int i=1;i<=num[item][0];i++)
{
int w=num[item][i];
money+=c[w];
score+=s[w];
}
printf("Case #%d:\n",ca++);
printf("%lld %lld\n",score,money);
for(int i=1;i<=num[item][0];i++)
printf("%d%c",num[item][i],i==num[item][0]?'\n':' ');
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: