度度熊的午饭时光
Accepts: 346
Submissions: 5127
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
一开始题目没有提示,后来加上了
坑点主要是要输出路径,而且这个路径必须满足序号之和最小,并且在这个情况下字典序最小
记录路径我是开了二维数组:
dp[x][y].val表示遍历到第x个物品总费用为y的情况下最大价值
dp[x][y].sum表示当前序号之和,如果最大价值相同,当然取序号和最小的
dp[x][y].pre表示你取的最后一个物品编号,因为dp时就是物品编号小到大的顺序dp的所以这个一定是当前最小
(如果dp[x][y]可以从某个物品转移过来,很显然dp[x][y].pre==x,
如果不能转移就让dp[x][y].pre==dp[x-1][y].pre)
具体转移看程序吧
#include<stdio.h>
#include<string.h>
#define inf 1044266558
typedef struct
{
int val;
int p;
}Res;
typedef struct
{
int val;
int pre;
int sum;
}Bet;
Bet dp[105][1005];
Res s[105];
int p[105];
int main(void)
{
int T, V, n, i, j, k, ans, sum, now, ts, cas = 1;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &V, &n);
for(i=1;i<=n;i++)
scanf("%d%d", &s[i].val, &s[i].p);
memset(dp, 62, sizeof(dp));
dp[0][0].val = dp[0][0].sum = dp[0][0].pre = 0;
for(i=1;i<=n;i++)
{
for(j=V;j>=s[i].p;j--)
{
dp[i][j] = dp[i-1][j];
if((dp[i][j].val<dp[i-1][j-s[i].p].val+s[i].val || dp[i][j].val==inf) && dp[i-1][j-s[i].p].val<inf)
{
dp[i][j].val = dp[i-1][j-s[i].p].val+s[i].val;
dp[i][j].pre = i;
dp[i][j].sum = dp[i-1][j-s[i].p].sum+i;
}
else if(dp[i][j].val==dp[i-1][j-s[i].p].val+s[i].val)
{
if(dp[i][j].sum>dp[i-1][j-s[i].p].sum+i)
{
dp[i][j].pre = i;
dp[i][j].sum = dp[i-1][j-s[i].p].sum+i;
}
}
}
for(;j>=0;j--)
dp[i][j] = dp[i-1][j];
}
ans = sum = -1, k = 0;
for(i=V;i>=0;i--)
{
if(dp[n][i].val<inf && dp[n][i].val>ans)
ans = dp[n][i].val, sum = i, ts = dp[n][i].sum;
else if(dp[n][i].val==ans)
{
if(dp[n][i].sum<ts)
sum = i, ts = dp[n][i].sum;
}
}
printf("Case #%d:\n%d %d\n", cas++, ans, sum);
now = n;
while(dp[now][sum].pre)
{
p[++k] = dp[now][sum].pre;
ts = dp[now][sum].pre;
now = ts-1;
sum -= s[ts].p;
}
if(k==0)
continue;
printf("%d", p[k]);
for(i=k-1;i>=1;i--)
printf(" %d", p[i]);
printf("\n");
}
return 0;
}