博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ-1010 Stamps
阅读量:6348 次
发布时间:2019-06-22

本文共 6437 字,大约阅读时间需要 21 分钟。

【题目描述】

题目大意是:邮票发行商会发行不同面值、不同种类的邮票给集邮爱好者,集邮爱好者有总目标面额,通过不同的邮票组合(总数在4张以内)达到该面值,卖给集邮爱好者。另外,发行商发行的邮票面值最多25种,但有可能同种面值有好几种邮票,甚至超过25种。

最佳方案满足以下要求:

  • 邮票种类数最多;
  • 如果种类数相同,则张数少者,更优;
  •  如果张数也相同,则单张面值最大者;
  • 如果以上都相同,则无最佳方案(平局tie);

 

【思路分析】

1. 邮票种类存储策略

由于最多只有四张邮票给集邮爱好者,我们可以设定同一面值的邮票最多存储5种,因为再多的种类组成的总价值也是一样的,输出的格式也一样。

这里取5种是因为要判断是否有tie的情况,设想某种邮票有N种(N>4),且这N种中任取4种为最优解时,此时应该输出”tie”,而如果只取4种,是不会输出”tie”。

所以,25种面值*最多存储的5种=125,为邮票的存储空间。HasMaxSameStamp函数判断该面值邮票是否已经达到5种。

int stamps[126];        // 存储邮票种类int stampType;          // 邮票种类数bool HasMaxSameStamp(int newstamp){    int hasSameNum = 0;    for (int i(0); i < stampType; i++)    {        if (stamps[i] == newstamp)        {            hasSameNum += 1;            if (hasSameNum >= 5)                return true;        }    }    return false;}

 

2. 深度优先法搜索所有解

解为最多四张邮票,用int solution[4]暂时存储进行搜索,noOfStamp为当前考虑的solution[noOfStamp]中的邮票,lastIndex为了避免重复搜索,将不搜索已搜索过的邮票定为策略,其意义为接下来的解只从数组编号为lastIndex的邮票开始搜索。

void FindStampsCombination(int solution[4], int noOfStamp, int lastIndex){    if (IsASolution(solution))    {        int *p = new int[4];        memcpy(p, solution, sizeof(int)*4);        solutions.push_back(p);        return ;    }     if (noOfStamp >= 4)        // 邮票数已经为4张,应该被剪枝,回溯        return ;            for (int stampindex( lastIndex ); stampindex < stampType; stampindex++)    {                        solution[noOfStamp] = -1;      }}

 

3. 找出最优解

将所有解存入vector<int*> solutions中,以题目要求的比较策略进行排序比较。先比较类型数,更多的取胜;再比较数量,少的取胜;最后比较单张面值最大的。

typedef struct solutionattributes{    int No;    int Types;    int Number;    int Max;}SolutionAttributes;int CompareSolution(const void* a, const void* b){    SolutionAttributes *pa = (SolutionAttributes*)a;    SolutionAttributes *pb = (SolutionAttributes*)b;    if ((*pa).Types != (*pb).Types)    {        return (*pb).Types - (*pa).Types;    }     else if ((*pa).Number != (*pb).Number)    {        return (*pa).Number - (*pb).Number;    }    else    {        return (*pb).Max - (*pa).Max;            }}

 

【小结】

本题关注的要点在于:DFS搜索(及剪枝、回溯),比较函数的编写规则,以及集合set的用法

1. 回溯法的程序编写见本题的“2.深度优先法搜索所有解”;

2. 比较函数规则:参数a, b,如果返回大于0,则a到b的后面去,记住这一原则即可;

3. 集合set的用法:

set
myset;myset.insert(10); // 插入set
::iterator set_it = myset.find(11); // 查找myset.count(7); // 计数myset.erase(10); // 删除// 遍历set
::iterator it; //定义前向迭代器 // 反向迭代器:set
::reverse_iterator for(it = myset.begin(); it != myset.end(); it++) { //...}

 

【附:完整源码】

#include 
#include
#include
using namespace std;typedef struct solutionattributes{ int No; int Types; int Number; int Max;}SolutionAttributes;int stamps[126]; // 存储邮票种类int stampType; // 邮票种类数int customer;vector
solutions;void InitialForStamps();bool HasMaxSameStamp(int newstamp);void FindStampsCombination(int solution[4], int noOfStamp, int lastIndex);bool IsASolution(int s[4]);int Compare(const void* a, const void* b);void OutputBestSolution();int CountTypes(int s[4]);int CountNumber(int s[4]);int CountMax(int s[4]);int CompareSolution(const void* a, const void* b);int main(){ int stampValue; while (scanf("%d", &stampValue) != EOF) { // 读取邮票种类 InitialForStamps(); while (true) { if (stampValue == 0) break; if ( !HasMaxSameStamp(stampValue) ) { stamps[ stampType++ ] = stampValue; } cin>>stampValue; } // 读取顾客需求,并处理,输出 while (true) { cin>>customer; if (customer == 0) break; solutions.clear(); int solution[4] = {-1,-1,-1,-1}; // 四张邮票 FindStampsCombination(solution, 0, 0); OutputBestSolution(); } } return 0;}void InitialForStamps(){ memset(stamps, 0, sizeof(stamps)); stampType = 0;}bool HasMaxSameStamp(int newstamp){ int hasSameNum = 0; for (int i(0); i < stampType; i++) { if (stamps[i] == newstamp) { hasSameNum += 1; if (hasSameNum >= 5) return true; } } return false;}void FindStampsCombination(int solution[4], int noOfStamp, int lastIndex){ if (IsASolution(solution)) { int *p = new int[4]; memcpy(p, solution, sizeof(int)*4); solutions.push_back(p); return ; } if (noOfStamp >= 4) // 邮票数已经为4张,应该被剪枝,回溯 return ; for (int stampindex( lastIndex ); stampindex < stampType; stampindex++) { solution[noOfStamp] = stampindex; FindStampsCombination(solution, noOfStamp+1, stampindex); solution[noOfStamp] = -1; }}bool IsASolution(int s[4]){ int stampsTotalValue = 0; for (int i(0); i < 4; i++) { stampsTotalValue += (s[i] < 0? 0 : stamps[ s[i] ]); } return (stampsTotalValue == customer);}int Compare(const void* a, const void* b){ int *pa = (int*)a; int *pb = (int*)b; return (*pa) - (*pb);}void OutputBestSolution(){ SolutionAttributes *sap = new SolutionAttributes[solutions.size()]; for (int i(0); i < solutions.size(); i++) { sap[i].No = i; sap[i].Types = CountTypes(solutions.at(i)); sap[i].Number = CountNumber(solutions.at(i)); sap[i].Max = CountMax(solutions.at(i)); } qsort(sap, solutions.size(), sizeof(sap[0]), CompareSolution); if (solutions.size() == 0) { cout<
<<" ---- none"<
1 && sap[0].Types == sap[1].Types && sap[0].Number == sap[1].Number && sap[0].Max == sap[1].Max) { cout<< customer <<" ("<< sap[0].Types <<"): "<<"tie"<
= 0) { cout<<" "<
types; for (int i(0); i < 4; i++) { if (s[i] >= 0) types.insert(s[i]); } return types.size();}int CountNumber(int s[4]){ int empty = 0; for (int i(0); i < 4; i++) { empty += (s[i] < 0); } return 4 - empty;}int CountMax(int s[4]){ int max = 0; for (int i(0); i < 4; i++) { if (s[i] >= 0) { max = max > stamps[ s[i] ]? max : stamps[ s[i] ]; } } return max;}int CompareSolution(const void* a, const void* b){ SolutionAttributes *pa = (SolutionAttributes*)a; SolutionAttributes *pb = (SolutionAttributes*)b; if ((*pa).Types != (*pb).Types) { return (*pb).Types - (*pa).Types; } else if ((*pa).Number != (*pb).Number) { return (*pa).Number - (*pb).Number; } else { return (*pb).Max - (*pa).Max; }}

转载于:https://www.cnblogs.com/xcwu/p/4128671.html

你可能感兴趣的文章
无缝轮播
查看>>
CTS失败项分析(2)android.telephony.cts.VisualVoicemailServiceTest#testFilter_data
查看>>
三分钟,轻松了解Dapp
查看>>
GMQ交易平台满足不同客户群体的多种投资需求
查看>>
大数据开发如何入门你必须知道这些
查看>>
关于js(es5)如何优雅地创建对象
查看>>
阿里云前端周刊 - 第 28 期
查看>>
iOS 主队列同步造成死锁的原因
查看>>
es6 下比较对象是否有修改的简要方法
查看>>
windows安装mysql
查看>>
你还在看《深入理解Java虚拟机》的运行时数据模型吗?
查看>>
RIS,创建 React 应用的新选择
查看>>
线性结构上的动态规划--算法竞赛入门经典笔记
查看>>
面试官:你使用webpack时手写过loader,分离过模块吗?
查看>>
PJSIP 学习进度
查看>>
Ubuntu 16.04系统下 对OpenJDK编译好的Hotspot 进行调试
查看>>
00-利用思维导图梳理JavaSE基础知识-持续更新中!
查看>>
java中三种注释及其实际应用的意义
查看>>
Emacs 24.2 for Mac OS X 最新版的 MAC Emacs 安装包
查看>>
让龙芯小本真正发挥作用-用8089D打造自己的Github服务器
查看>>