#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/*
编写程序对于邮票的组合执行组合 并挑选出最优解
题目要求如下:
要求输入表示邮票的面值若干 不超过 25 个 对于输入的邮票 即使面值相同,同样视为不同的邮票种类
然后需要将该些邮票来进行组合并交给不同的客户,客户有一系列的数字组成
要求将给出的邮票进行组合 每个组合不能超过4张邮票 尽量交给客户端不同种类的邮票
1. 如果 存在不同种类相同的组合,那么按种类相同数量最少的最优
2. 如果 种类相同数量相同 那么单值最大的最优
3. 如果 仍存在同等 那么打印tie
*/
const int MAX_DIF_TYPES = 25; //最大的输入的不同种类
const int MAX_TYPES = 4; //最大交给客户的种类数量
int nTotalStampCount; //表示输入邮票的数量
struct BestCombination //保存最优组合的信息
{
int nMaxStampValue; //最大的邮票面值
int nStampType; //最大的邮票不同种类
int nCountComb; //组合最少的邮票数量(在邮票不同种类相同的情况下)
int mResultComb[MAX_TYPES]; //保存最优的结果集
bool bFlagTie; //是否平局
};
BestCombination gCombResult; //保存最优组合结果
int mAllStampValue[MAX_DIF_TYPES]; //保存所有的输入邮票面值
void GetBestCombResult(int tmpStampComb[],int &nCountStamp,int& nTypeStamp,int customVal,int start);
void UpdateBestComb(int tmpStampComb[],int &nCountStamp,int& nTypeStamp,int nMaxStampValue);
void CopyCombResult(int tmpStampComb[], int &nCountStamp, int& nTypeStamp, int nMaxStampValue);
int GetMaxVaule(int mArray[], int nSize);
int main()
{
vector<int> customVec; //保存用户需求
while (true)
{
int tmp_stamp;
int dif_stamp[MAX_DIF_TYPES] = {0}; //输入的不同邮票
nTotalStampCount = 0;
while (true)
{
if (scanf_s("%d",&tmp_stamp) == EOF) exit(0);
if (tmp_stamp <= 0 || nTotalStampCount >= MAX_DIF_TYPES)
break;
///相同面值的邮票数量大于等于5 设置为5 剪枝操作
if (dif_stamp[tmp_stamp - 1] < 5)
{
dif_stamp[tmp_stamp - 1]++;
mAllStampValue[nTotalStampCount++] = tmp_stamp;
}
}
///输入邮票的种类完成 需要对数据进行处理了。
sort(mAllStampValue, mAllStampValue + nTotalStampCount); //对邮票面值进行从小到大的排序
///每次清空顾客数据
customVec.clear();
while (cin >> tmp_stamp && tmp_stamp)
{
customVec.push_back(tmp_stamp); //录入客户需求
}
for (int i = 0; i < customVec.size(); ++i)
{
int tmpStampCombCount = 0;
int tmpStampCombType = 0;
int tmpStampComb[MAX_TYPES] = { 0 };
///对每个用户都进行数据上的处理,获取最优解
memset(&gCombResult, 0, sizeof(gCombResult)); //首先对数据进行初始化
GetBestCombResult(tmpStampComb,tmpStampCombCount,tmpStampCombType,customVec[i],0); //获取组合的最优解
////打印结果
if (gCombResult.nStampType <= 0)
cout << customVec[i] << " ---- none" << endl;
else if (gCombResult.bFlagTie)
cout << customVec[i] << " (" << gCombResult.nStampType << "): tie" << endl;
else
{
cout << customVec[i] << " (" << gCombResult.nStampType << "):";
for (int i = 0; i < gCombResult.nCountComb; ++i)
cout << " " << gCombResult.mResultComb[i] ;
cout << endl;
}
}
}
return 0;
}
////递归 回溯法来计算出最优解
void GetBestCombResult(int tmpStampComb[], int& nCountStamp, int& nTypeStamp, int customVal, int start)
{
if (customVal < 0) return; //组合失败的清空下 返回
if (customVal == 0) //找到了一种组合
{
UpdateBestComb(tmpStampComb, nCountStamp, nTypeStamp, GetMaxVaule(tmpStampComb, nCountStamp));
}
else
{
for (int i = start; i < nTotalStampCount; ++i) //对于每一个面值的数字 都进行组合计算
{
if (mAllStampValue[i] > customVal || nCountStamp >= MAX_TYPES) break; //无法进行适当的组合 ,剪枝操作
if (i > start || nCountStamp <= 0) //如果当i进行循环也就表示了进行了不同种类的组合 需要自增不同种类数
++nTypeStamp;
tmpStampComb[nCountStamp++] = mAllStampValue[i];
///回溯调用函数 函数返回时 运行之后的代码
GetBestCombResult(tmpStampComb, nCountStamp, nTypeStamp, customVal - mAllStampValue[i], i);
///重置状态
if (i > start || nCountStamp == 1) //该部分的依据是 如果是进行种类相同的组合 则回溯到种类0 如果是不同种类的组合 每次递减一个种类继续组合
--nTypeStamp; //这样能够求出对于要求的所有解
--nCountStamp;
}
}
}
void UpdateBestComb(int tmpStampComb[], int & nCountStamp, int & nTypeStamp, int nMaxStampValue)
{
///当前不同种类数大于之前种类数的时候
if (nTypeStamp > gCombResult.nStampType)
{
CopyCombResult(tmpStampComb, nCountStamp, nTypeStamp, nMaxStampValue);
}
///当种类相同的时候
else if (nTypeStamp == gCombResult.nStampType)
{
if (nMaxStampValue > gCombResult.nMaxStampValue) //比较最大单值
CopyCombResult(tmpStampComb, nCountStamp, nTypeStamp, nMaxStampValue);
else if(nMaxStampValue == gCombResult.nMaxStampValue)
gCombResult.bFlagTie = true; //将标志位设置为真
}
}
void CopyCombResult(int tmpStampComb[], int & nCountStamp, int & nTypeStamp, int nMaxStampValue)
{
gCombResult.nCountComb = nCountStamp;
gCombResult.nMaxStampValue = nMaxStampValue;
gCombResult.nStampType = nTypeStamp;
gCombResult.bFlagTie = false;
for (int i = 0; i < nCountStamp; ++i) gCombResult.mResultComb[i] = tmpStampComb[i];
}
int GetMaxVaule(int mArray[], int nSize)
{
int max = 0;
for (int i = 0; i < nSize; ++i)
if (mArray[i] > max)
max = mArray[i];
return max;
}
北大ACAM(1010STAMPS)代码
猜你喜欢
转载自blog.csdn.net/David_TD/article/details/83655973
今日推荐
周排行