题目链接:STAMPS
Description
Input
Output
Sample Input
1 2 3 0 ; three different stamp types
7 4 0 ; two customers
1 1 0 ; a new set of stamps (two of the same type)
6 2 3 0 ; three customers
Sample Output
7 (3): 1 1 2 3
4 (2): 1 3
6 ---- none
2 (2): 1 1
3 (2): tie
这题第一个难点就是读题了,看了很久又参考了别人翻译的才弄明白,这里抄过来~
题意:
给出n种邮票,每种邮票有自己的面值(面值可能重复)
指定m种“总面值”,对每种“总面值”,求解满足如下条件的组合以达到该“总面值”
(1) 所用邮票在n种中可以重复选取
(2) 所用邮票张数〈=4
(3) 尽量多的使用那个不同种类的邮票 Max (Stamp Types)
(4) 若有多种方案满足(3),则选取张数最小的一种方案 Min (Stamp Num)
(5) 若有多种方案满足(3)(4),则选取“最大面额”最高的一种方案。 Max(Heightest Value)
(6) 若有多种方案满足(3)(4)(5) 则输出 “tie”
主要思路:
1. 先对输入按面值的从小到大排序,这对剪枝有帮助,比如:
输入面值:1,2,3,4,5 顾客要求是 3
假如计算到分支 1,1,2 的时候,超过 3 了,后面的 1,1,3 ; 1,1,4 ; 1,1,5 都不需要计算了
2. 对解的评价,采用了一个计算公式,省去了较复杂的条件判断
评价分数 = 种类数 * 100 + (4 - 邮票数) * 10 + 最大面值;
3. 对解中邮票的种类数,这个不太好弄
我用了个数组,记录序号,这个方法有点笨拙,大家有好的方法告诉我吧,吼吼~
其实我的方法类似于穷举了,一开始想用广度优先,总之大家有什么高见告诉我吧。
下面是源代码:
#include
#include
using namespace std;
int stamps[100]; //存放邮票的种类(有人说只分配 25 种会不过)
int result[4]; //存放最终结果
int curresult[4]; //存放当前结果
int goal; //顾客要求的面值
int num; //邮票种类数
bool tie = false; //判断是否有tie
int score = 0; //最优解的分数
int curscore = 0; //当前解的分数
int cards = 0; //最优解中有多少张邮票
int curcards = 0; //当前解中有多少张邮票
int kinds[4]; //记录类型的数组
int kindsnum = 0; //最优解中有多少种邮票
int curkindsnum = 0;//当前解中有多少种邮票
void DFS(int cur, int index, int curcards)
{
if((curcards > 3) && (cur != goal)) return; //失败了,剪枝
if(cur == goal) //成功了,开始评分
{
curkindsnum = 1;
for(int i = 1; i < curcards; i++)
{
if(kinds[i] != kinds[i-1])
curkindsnum++;
}
curscore = curkindsnum * 100 + (4 - curcards) * 10 + stamps[index];
if(curscore == score)
{
tie = true;
}
else if(curscore > score)
{
tie = false;
score = curscore;
cards = curcards;
kindsnum = curkindsnum;
for(int i = 0; i < 4; i++)
result[i] = curresult[i];
}
return;
}
for(int i = index; i < num; i++)
{
if(cur + stamps[i] > goal) return; //剪枝
curresult[curcards] = stamps[i];
kinds[curcards] = i;
DFS(cur + stamps[i], i, curcards + 1);
}
return;
}
void Print()
{
if(!result[0])
{
cout << goal << " ---- none" << endl;
return;
}
if(tie)
{
cout << goal << " (" << kindsnum << "): tie" << endl;
return;
}
else
{
cout << goal << " (" << kindsnum << "): ";
for(int i = 0; i < cards; i++)
cout << result[i] << " ";
}
cout << endl;
}
int main()
{
while(true)
{
memset(stamps, 0, sizeof(stamps));
num = 0;
cin >> stamps[0];
if(!stamps[0]) break;
while(stamps[num])
{
cin >> stamps[++num];
}
sort(stamps, stamps + num); //从小到大排序
while(true)
{
memset(result, 0, sizeof(result));
cin >> goal;
if(goal == 0) break;
if(goal > 4 * stamps[num-1]) //加个判断,不过应该没什么作用
{
cout << goal << " ---- none" << endl;
continue;
}
score = 0;
DFS(0, 0, 0);
Print();
}
}
return 0;
}