电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
输入格式:
多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束
输出格式:
对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
解法一:利用二进制,&运算生成子集,暴力破解
#include <iostream>
#include<math.h>
using namespace std;
const int MAX_RESULT=1001;
int main()
{
int n,result,money,temp;
while(cin>>n,n){
int price[n];
for (int i=0;i<n;i++)
{
cin>>price[i];
}
cin>>money;
result=MAX_RESULT;
for (int i=0;i<pow(2,n);i++)
{
temp=money; //temp作为临时变量存储钱数,每一种情况都要初始化
for (int j=0;j<n;j++) //第i+1位,也就是第i个菜品
{
if((i&(1<<j))&&temp>=5)
temp-=price[j];
}
//cout<<result<<" ";
if(result>temp)
result=temp;
}
cout<<result<<endl;
}
return 0;
}
解法二:变形动态规划
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_LENGTH = 1005;
int price[MAX_LENGTH];
int n;
int balance;
int F[1005];
int getMaxConsumption(){
for (int i = 0; i < n-1; i++)
{
for (int V = balance; V >=price[i]; V--){
F[V] = max(F[V], F[V - price[i]] + price[i]);
}
}
return F[balance];
}
int main(){
while (cin>>n)
{
if (n == 0) break;
memset(price, 0, sizeof(int)*n);
for (int i = 0; i < n; i++)
{
scanf("%d", &price[i]);
}
scanf("%d", &balance);
if (balance < 5){ //特殊情况考虑
printf("%d\n", balance);
continue;
}
balance -= 5;
for (int i = 0; i < balance+1; i++) //范围数组balance+1
{
F[i] = 0;
}
sort(price, price + n);
int result = getMaxConsumption();
printf("%d\n", balance-result-price[n-1]+5);//原始值尽量别改变,声明新变量作为中间值
}
return 0;
}
注意事项
1.对子集的表示pow(2,n),用二进制来表示
2.初始化问题要注意
3.DP的变形,一是在有个>5的限制,还有个是求最小值,最后一个是value数组和weight数组合而为一