仅供参考学习使用,谢谢
问题描述:
贫瘠之地上有很多怪,战胜它们会获得它们身上的金币,不过跟它们战斗的勇士也会受到攻
击,损失一定的血和蓝,无论血和蓝哪个没有了,勇士都会挂掉。Alice在这里打怪,她不想
挂掉,那她最多可以赚到多少金币呢?
- 输入:
第一行有三个数,Alice的血量和蓝量、怪的个数。第二行开始,每行三个数,是与每
个怪决斗会损失的血量和蓝量,以及获得的金币数。(所有数都是自然数)
- 输出:
Alice能够获得的最大金币数。
思路分析:
二维背包问题(多加一个01背包即可)
01背包问题的状态转换方程:
f[i][v1][v2] = Max{f[i-1][v1][v2], f[i-1][v1-c1[i]][v2-c2[i]]+w[i]}
该问题是一个01背包问题的简单变形,首先要将这个问题分成子问题,然后优化子结构。
根据01背包问题的思想,按照顺序打N个怪物,且逐个考虑 血和蓝 为11~RedBlue每个点所能产生的最大价值
这样每个点 Red*Blue内所能产生的最大价值仅和上一个怪物的产生价值有关,即满足了 无后效性 和 逆向组解
考虑某红蓝值时 某怪物的最大价值 需要考虑
a=该红蓝值对应点所含红蓝值 减去 当前怪物所消耗的红蓝 在前一个怪物所产生的最大价值+当前怪物所能产生的价值
b=该红蓝值对应点 在上一个怪物所能产生的最大价值
如果a>b则该时间段在该怪物所能产生的最大价值是情况a所能产生的最大价值,否则是情况b所能产生的最大价值
算法描述:
1. typedef
需要一个int型一维数组red用于记录每一个怪物所消耗的红,
一个int型一维数组blue用于记录每一个怪物所消耗的蓝,
一个int型一维数组value用于记录每一个怪物所能产生价值,
一个int型二维数组f用于记录在 每一个怪物 某一红蓝值 所能产生的最大价值
2. init函数来初始化
由于该问题需要逆向组解,即先将f的最后一行(从最后一个金矿向第一个金矿移动)
最后一个金矿的每一个时间段所能产生的最大价值进行输入,同时需要将f[i][0][0],time[0],value[0]初始化为0
3. workout函数
计算每一个怪物 每一点对应红蓝值 所能产生的最大价值 并填入f表中
从倒数第二个怪物开始移动 可以使用的总红蓝 每多出一点红一点蓝 就要考虑当前时间段是否已经达到这个怪物所要消耗的红蓝值 如果已经达到则需要判断:
a=该红蓝值对应点所含红蓝值 减去 当前怪物所消耗的红蓝 在前一个怪物所产生的最大价值+当前怪物所能产生的价值
b=该红蓝值对应点 在上一个怪物所能产生的最大价值
如果a>b则该时间段在该怪物所能产生的最大价值是情况a所能产生的最大价值,否则是情况b所能产生的最大价值
测试数据:
- 数据1:
100 10 4
101 2 88
20 7 36
40 1 23
10 5 30
- 结果1:
59
- 数据2:
100 30 6
91 5 90
48 16 72
36 17 70
55 3 60
8 40 99
10 14 23
- 结果2:
142
#include <stdio.h>
#define maxsize 1000
typedef struct {
int red[maxsize+1];
int blue[maxsize+1];
int value[maxsize+1];
int f[maxsize+1][maxsize+1];//N,red,blue
}Bag;
Bag create(int Red, int Blue, int N){
Bag Alice;
//初始化 f[i][j]
Alice.red[0]=0;
Alice.blue[0]=0;
Alice.value[0]=0;
for (int x=0; x<Red+1; x++)
for (int y=0; y<Blue+1; y++)
Alice.f[x][y]=0;
//给 red[] & blue[] & value[] 赋值
for (int i=1; i<=N; i++) {
int red=0,blue=0,value=0;
scanf("%d%d%d",&red,&blue,&value);
Alice.red[i]=red;
Alice.blue[i]=blue;
Alice.value[i]=value;
}
for (int z=1; z<=N; z++){
for (int x=Red; x>=Alice.red[z]; x--) {//这里是为了避免成为二维完全背包,所以 -- 而不是 ++
for (int y=Blue; y>=Alice.blue[z]; y--) {
if (Alice.f[x][y]>Alice.f[x-Alice.red[z]][y-Alice.blue[z]]+Alice.value[z]) {
Alice.f[x][y]=Alice.f[x][y];
} else {
Alice.f[x][y]=Alice.f[x-Alice.red[z]][y-Alice.blue[z]]+Alice.value[z];
}
}
}
}
// for (int x=1; x<=Red; x++) {
// for (int y=1; y<=Blue; y++) {
// printf("%3d",Alice.f[x][y]);
// }
// printf("\n");
// }
return Alice;
}
Bag workout (int Red, int Blue, int N, Bag Alice){
for (int z=1; z<=N; z++){
for (int x=Red; x>=Alice.red[z]; x--) {
for (int y=Blue; y>=Alice.blue[z]; y--) {
if (Alice.f[x][y]>Alice.f[x-Alice.red[z]][y-Alice.blue[z]]+Alice.value[z]) {
Alice.f[x][y]=Alice.f[x][y];
} else {
Alice.f[x][y]=Alice.f[x-Alice.red[z]][y-Alice.blue[z]]+Alice.value[z];
}
}
}
}
return Alice;
}
int main(int argc, const char * argv[]) {
int Red=0,Blue=0,N=0;//Red&Blue的含义在背包问题中等价于背包总承重,N相当于怪物个数
scanf("%d%d%d",&Red,&Blue,&N);
Bag Alice=create(Red, Blue, N);
// Alice=workout(Red, Blue, N, Alice);
printf("%d\n",Alice.f[Red][Blue]);
return 0;
}