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端去,电话公司发好心免费送你几段不用拉网线,剩下的费用等于剩余最长电话线的长度,要你求出最小的费用. 这一看又是一个 ...
随机推荐
- .net 资源
基于.net构架的留言板项目大全源码 http://down.51cto.com/zt/70 ASP.net和C#.net通用权限系统组件功能教程 http://down.51cto.com/zt/1 ...
- Android 仿360桌面小人
首先自定义FloatsWindowView,用于显示动画小人. import android.annotation.SuppressLint; import android.content.Conte ...
- 定义一个runtime的Annotation
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(value ...
- symfony2-不同bundle的entity的一对多关系
重点:其实和普通一个bundle中一样,只是把entity地址写全就行. 例子: 表commentone (多方) 表shopone(一方) 在Userbundle中的Commentone实体对应关系
- 树莓派高级GPIO库,wiringpi2 for python使用笔记(四)实战DHT11解码
DHT11是一款有已校准数字信号输出的温湿度传感器. 精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃. 我买的封装好的模块,上边自带了上拉电阻,直接查到树莓派上即可灰 ...
- [LeetCode]题解(python):141-Linked List Cycle
题目来源: https://leetcode.com/problems/linked-list-cycle/ 题意分析: 给定一个链表,判断链表是否有环.要求O(1)空间时间复杂度. 题目思路: 用快 ...
- oracle plsql 64位 32位连接未打开 无法解析各种错终极解决方案
首先取消登陆,进入pl/sql界面-工具-首选项 其次就需要你设置环境变量(加一个ORACLE_HOME和修改原先path里的路径这个不修改也行,主要是让大家知道为什么设置环境变量) 这些设置好,你在 ...
- Linux2.6中的Slab层
还记得一个进程创建的时候是什么给它分配的“进程描述符”吗?没错,是slab分配器,那么,这个slab分配器是个什么东西呢? 分配和释放数据结构是所有内核中最普遍的操作之一.为了 ...
- JavaFx初探
由于项目的须要,实在是没有办法了,试了非常多种方案(RCP,SWT,Flex,Smartinvoke...),终于还是决定開始研究JavaFx...为了给用户更好地体验我们的"智能家居&qu ...
- iOS中Block介绍 基础
ios开发block的使用指南,以及深入理解block的内存管理,也适用于osx开发.讨论范围:block的使用,内存管理,内部实现.不包含的内容:gc arc下的block内存,block在c++中 ...