严格意义上说,这是一道搜索题。
是的,这真的是一道不带一点遮掩的“暴!力!搜!索!”
我居然没看出来,最后是用DP做完的。。。
转移方程参考的背包问题,
我用了一个二维数组solution[i][j]
记录用 i 张邮票组合成 j 需求的最优组合情况。
转移方程为
solution[i][j]=best(solution[i-k][j-stamp[x]*k])
时间复杂度估算为O(n*m),其中n为面额数量,m为最大需求。
空间复杂度估算为O(m),m为最大需求值。
幸亏这题数据比较仁慈,要不就MLE了。
不过话说回来,要是数据恶心人的话,裸搜O(n^4)怎么看都会TLE。
这题比较神奇的地方在于,题目居然没有给数据范围,这真是。。。
好了,上代码,没懂得看注释
#include <iostream>
using namespace std;
class Solution{
public:
int type_num; //邮票种类
int stamp_num; //邮票总数
int max_stamp; //最大面额
int combination_num; //等价组合的数量
int stamp_combination[4]; //第一种组合
};
//flag记录两个方案的好坏,-1表示s方案更优,0表示相同,1表示更劣
int cmp(Solution s,int type_num,int stamp_num,int max_stamp) {
int flag;
if (type_num>s.type_num)
flag = 1;
else if (type_num<s.type_num)
flag = -1;
else if (stamp_num<s.stamp_num)
flag = 1;
else if (stamp_num>s.stamp_num)
flag = -1;
else if (max_stamp>s.max_stamp)
flag = 1;
else if (max_stamp<s.max_stamp)
flag = -1;
else
flag = 0;
return flag;
}
int main() {
Solution * solution[5]; //解决方案数组,题中没范围。
int n,need; //n代表面额总数,need代表顾客需求
int stamp[300]; //存储邮票面额,题中没给范围,试出来的。
int i,j,k,l,x,flag,type_num,stamp_num,max_stamp;
n=0;
while (cin>>stamp[n]) {
//读入邮票面额
do {
n++;
cin>>stamp[n];
}
while (stamp[n]);
//排序,居然要排序,居然还有隐藏条件要排序!!!
for (i=0;i<n;i++) {
j=i;
while (stamp[j-1]<stamp[j] && j) {
k=stamp[j-1];
stamp[j-1]=stamp[j];
stamp[j]=k;
j--;
}
}
//处理用户需要
while (cin>>need && need) {
//初始化
for (i=0;i<5;i++)
solution[i] = new Solution[need+1];
for (i=0;i<=need;i++)
for (j=0;j<5;j++)
solution[j][i].combination_num=0;
solution[0][0].type_num=0;
solution[0][0].stamp_num=0;
solution[0][0].max_stamp=0;
solution[0][0].combination_num=1;
for(i=0;i<n;i++)
for (j=need;j>=stamp[i];j--)
for (k=1;k<=4;k++)
for (l=0;l+k<5;l++)
if (j>=stamp[i]*k && solution[l][j-stamp[i]*k].combination_num) {
type_num = solution[l][j-stamp[i]*k].type_num+1;
stamp_num = solution[l][j-stamp[i]*k].stamp_num+k;
max_stamp = (solution[l][j-stamp[i]*k].max_stamp<stamp[i])?(stamp[i]):(solution[l][j-stamp[i]*k].max_stamp);
if (stamp_num>4)
continue;
//把新方案和原方案进行比较
flag = cmp(solution[l+k][j],type_num,stamp_num,max_stamp);
//按照flag更新组合方案
if (flag==1) { //更新
solution[l+k][j].type_num=type_num;
solution[l+k][j].stamp_num=stamp_num;
solution[l+k][j].max_stamp=max_stamp;
solution[l+k][j].combination_num=solution[l][j-stamp[i]*k].combination_num;
//更新组合方案
for (x=0;x<solution[l][j-stamp[i]*k].stamp_num;x++)
solution[l+k][j].stamp_combination[x]=solution[l][j-stamp[i]*k].stamp_combination[x];
for (x=solution[l][j-stamp[i]*k].stamp_num;x<stamp_num;x++)
solution[l+k][j].stamp_combination[x]=stamp[i];
/*
cout<<j<<"("<<type_num<<")--"<<solution[l+k][j].combination_num<<"--"<<max_stamp<<endl;
for (x=0;x<stamp_num;x++)
cout<<solution[l+k][j].stamp_combination[x]<<" ";
cout<<endl;
*/
}
else if (flag==0) { //更新同解数量
solution[l+k][j].combination_num++;
}
else if (flag==-1) { //舍弃该解
}
}
//找出最优解
j=0;
type_num=0;
stamp_num=0;
max_stamp=0;
for (i=4;i>0;i--) {
flag = cmp(solution[i][need],type_num,stamp_num,max_stamp);
if (flag==-1) {
type_num = solution[i][need].type_num;
stamp_num = solution[i][need].stamp_num;
max_stamp = solution[i][need].max_stamp;
j=i;
}
}
flag = j;
if (solution[flag][need].combination_num==1) {
cout<<need<<" ("<<solution[flag][need]. type_num<<"):";
for (i=solution[flag][need].stamp_num-1;i>=0;i--)
cout<<" "<<solution[flag][need].stamp_combination[i];
cout<<endl;
}
else if (solution[flag][need].combination_num>1)
cout<<need<<" ("<<solution[flag][need]. type_num<<"): tie"<<endl;
else
cout<<need<<" ---- none"<<endl;
}
for (i=0;i<5;i++)
delete solution[i];
n=0;
}
return 0;
}