POJ-1010 Stamps
【题目描述】
题目大意是:邮票发行商会发行不同面值、不同种类的邮票给集邮爱好者,集邮爱好者有总目标面额,通过不同的邮票组合(总数在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] = stampindex;
FindStampsCombination(solution, noOfStamp+1, 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<int> myset; myset.insert(10); // 插入
set<int>::iterator set_it = myset.find(11);
// 查找
myset.count(7); // 计数
myset.erase(10); // 删除 // 遍历
set<int>::iterator it; //定义前向迭代器
// 反向迭代器:set<int>::reverse_iterator
for(it = myset.begin(); it != myset.end(); it++)
{
//...
}
【附:完整源码】
#include <iostream>
#include <vector>
#include <set>
using namespace std; typedef struct solutionattributes
{
int No;
int Types;
int Number;
int Max;
}SolutionAttributes; int stamps[126]; // 存储邮票种类
int stampType; // 邮票种类数
int customer;
vector<int*> 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<<customer<<" ---- none"<<endl;
}
else if (solutions.size() > 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"<<endl;
}
else
{
cout<< customer <<" ("<< sap[0].Types <<"):"; int no = sap[0].No;
int tempStamps[4] = {-1, -1, -1, -1};
for (int i(0); i < 4; i++)
{
if (solutions.at(no)[i] != -1)
tempStamps[i] = stamps[ solutions.at(no)[i] ];
} qsort(tempStamps, 4, sizeof(tempStamps[0]), Compare);
for (int i(0); i < 4; i++)
{
if (tempStamps[i] >= 0)
{
cout<<" "<<tempStamps[i];
}
} cout<<endl;
}
} int CountTypes(int s[4])
{
set<int> 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;
} }
POJ-1010 Stamps的更多相关文章
- poj 1010
http://poj.org/problem?id=1010 题意:给你n种邮票的价值,到0结束,这些邮票价值有可能相同,但是形状是不同的. 还有给你m个收藏家所需要收藏的邮票的总价格.到0结束. 每 ...
- POJ 1010 题目翻译+题解
题目实在是太难懂了,我翻译了一下... STAMPS Description Have you done any Philately lately? 你最近有没有集邮? You have been h ...
- POJ题目排序的Java程序
POJ 排序的思想就是根据选取范围的题目的totalSubmittedNumber和totalAcceptedNumber计算一个avgAcceptRate. 每一道题都有一个value,value ...
- 51nod 1010 只包含因子2 3 5的数 && poj - 1338 Ugly Numbers(打表)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1010 http://poj.org/problem?id=1338 首先 ...
- POJ 2096 Collecting Bugs 期望dp
题目链接: http://poj.org/problem?id=2096 Collecting Bugs Time Limit: 10000MSMemory Limit: 64000K 问题描述 Iv ...
- POJ1010 Stamps
题目来源:http://poj.org/problem?id=1010 题目大意: 某邮局要设计新的邮资管理软件,依据顾客的需要和现有的面值给顾客分派邮票. 该邮局有很多顾客是集邮爱好者.这些人希望得 ...
- POJ 题目分类(转载)
Log 2016-3-21 网上找的POJ分类,来源已经不清楚了.百度能百度到一大把.贴一份在博客上,鞭策自己刷题,不能偷懒!! 初期: 一.基本算法: (1)枚举. (poj1753,poj2965 ...
- poj 3268(spfa)
http://poj.org/problem?id=3268 对于这道题,我想说的就是日了狗了,什么鬼,定义的一个数值的前后顺序不同,一个就TLE,一个就A,还16MS. 感觉人生观都奔溃了,果然,题 ...
- POJ 2570(floyd)
http://poj.org/problem?id=2570 题意:在海底有一些网络节点.每个节点之间都是通过光缆相连接的.不过这些光缆可能是不同公司的. 现在某个公司想从a点发送消息到b点,问哪个公 ...
- Divide and conquer:Telephone Lines(POJ 3662)
电话线 题目大意:一堆电话线要你接,现在有N个接口,总线已经在1端,要你想办法接到N端去,电话公司发好心免费送你几段不用拉网线,剩下的费用等于剩余最长电话线的长度,要你求出最小的费用. 这一看又是一个 ...
随机推荐
- centos 安装mysql密码修改后还是不能连接的原因
centos 上安装mysql密码修改后还是不能连接出现错误:ERROR 1142 (42000): SELECT command denied to user ''@'localhost' for ...
- R与数据分析旧笔记(十一)数据挖掘初步
PART 1 PART 1 传统回归模型的困难 1.为什么一定是线性的?或某种非线性模型? 2.过分依赖于分析者的经验 3.对于非连续的离散数据难以处理 网格方法 <Science>上的文 ...
- Java之工厂模式
interface Fruit { void eat(); } class Apple implements Fruit { public void eat() { S ...
- mysql 函数执行权限
mysql> show grants for query_all@'115.236.1x0.x'; +---------------------------------------------- ...
- Android多线程任务优化1:探讨AsyncTask的缺陷
AsyncTask还有别的缺陷,在生成listview的时候,如果adapter里面的count动态改变的话,不能使用AsyncTask,只能使用Thread+Handler,否则会出现如下错误 j ...
- iOS中菊花。。。
其实系统的菊花除了功能有点单一,不具有刷新页面的功能以外,其他都还好吧,满足你一些正常的提示功能还是绰绰有余的:直接把项目里面的代码粘出来吧,其实也没有什么特别要注意的地方,一些设置属性也算留个备份 ...
- Linux系统编程——进程调度浅析
概述 操作系统要实现多进程.进程调度不可缺少. 有人说,进程调度是操作系统中最为重要的一个部分.我认为这样的说法说得太绝对了一点,就像非常多人动辄就说"某某函数比某某函数效率高XX倍&quo ...
- VS2015 启用“仅我的代码”
在调试网站的时候,如果不勾选 [启用"仅我的代码"],会跳出一大堆异常,但是异常不作处理,非常烦人: 解决办法就是在 [调试]->[选项]->[勾选 启用"仅 ...
- [MSSQL]从SQL语句的角度 提高数据库的访问性能
1.什么是执行计划?执行计划是依赖于什么信息. 2. 统一SQL语句的写法减少解析开销 3. 减少SQL语句的嵌套 4. 使用“临时表”暂存中间结果 5. OLTP系统SQL语句必须采用绑定变量 6. ...
- 入Lucene的第一个坑
兴致勃勃的下载了Lucene6的Jar包,打算跑个Demo看下它神奇的魅力,结果一运行就出错了 Exception in thread "main" java.lang.Unsup ...