Uva11450 Wedding shopping
题目: 链接
有C个商店和M数量的钱,每个商店有若干不同价格的衣服,需要在每个商店都买一件衣服,并且最终花费的钱需要最大(但不大于M),问最多的花费是多少?如果不能在每个店都买一件衣服,那么输出no solution
样例输入:
3
100 4
3 8 6 4
2 5 10
4 1 3 3 7
4 50 14 23 8
20 3
3 4 6 8
2 5 10
4 1 3 5 5
5 3
3 6 4 8
2 10 6
4 7 3 1 7
样例输出:
75
19
no solution
思路:
- 一个dp问题,假设我们依次在商店0, 1, 2...购买衣服,用g表示当前购买的商店的序号,money表示当前余下的钱。reachable[g][money]数组表示在商店g购买一件衣服后剩余money的数量,其值为true,表示此种状态可以达到,否则该状态不成立,依次填写表格,最后看在第C家商店能否有reachable[C-1][money]=true的状态,有的话找到money最小的那个,即是最多的花费,否则失败。
代码:
#include <iostream>
#include <memory.h>
using namespace std;
const int maxm = 205;
const int maxc = 25;
int price[maxm][maxc];
bool reachable[maxc][maxm]; //for i'th garment, whether we can fetch one thing and the remaining monney
int main(){
freopen("uva_input.txt", "r", stdin);
freopen("uva_output.txt", "w", stdout);
int N; scanf("%d", &N);
//printf("%d", N);
while(N--){
int M, C;
scanf("%d%d", &M, &C);
for(int i = 0;i < C; ++i){
scanf("%d", &price[i][0]);
for(int j = 1; j <= price[i][0]; ++j) scanf("%d", &price[i][j]);
}
memset(reachable, false, sizeof(reachable));
for(int i = 1; i <= price[0][0]; ++i){ //initial condition, for garment 0
reachable[0][M-price[0][i]] = true;
}
for(int g = 1; g < C; ++g){
for(int money = 0; money <= M; ++money){
if(reachable[g-1][money]){
for(int k = 1; k <= price[g][0]; ++k){
reachable[g][money-price[g][k]] = true;
}
}
}
}
int money;
for(money = 0; money <= M && !reachable[C-1][money]; ++money); // after C garment, find the reachable solutions
if(money == M+1) printf("no solution\n");
else printf("%d\n", M-money);
}
}
Note:
- 这里的reachable数组可以优化,因为在计算第g家商店的各状态时,只与从g-1家商店出来后的状态有关,与先前其它状态无关,因此用reachable[2][money]即可表示状态,在各商店购买一件衣服后剩余钱的状态即滚动地在这个row为2的二位数组中记录。
代码:
#include <iostream>
#include <memory.h>
using namespace std;
const int maxm = 205;
const int maxc = 25;
int price[maxm][maxc];
bool reachable[2][maxm]; //for i'th garment, whether we can fetch one thing and the remaining monney
int main(){
freopen("uva_input.txt", "r", stdin);
freopen("uva_output.txt", "w", stdout);
int N; scanf("%d", &N);
//printf("%d", N);
while(N--){
int M, C;
scanf("%d%d", &M, &C);
for(int i = 0;i < C; ++i){
scanf("%d", &price[i][0]);
for(int j = 1; j <= price[i][0]; ++j) scanf("%d", &price[i][j]);
}
memset(reachable, false, sizeof(reachable));
for(int i = 1; i <= price[0][0]; ++i){ //initial condition, for garment 0
reachable[0][M-price[0][i]] = true;
}
int idx = 0;
for(int g = 1; g < C; ++g){
memset(reachable[!idx], false, sizeof(reachable[!idx]));
for(int money = 0; money <= M; ++money){
if(reachable[idx][money]){
for(int k = 1; k <= price[g][0]; ++k){
reachable[!idx][money-price[g][k]] = true;
}
}
}
idx = !idx;
}
int money;
for(money = 0; money <= M && !reachable[idx][money]; ++money); // after C garment, find the reachable solutions
if(money == M+1) printf("no solution\n");
else printf("%d\n", M-money);
}
}