题目大意
给你一些邮票的面值,然后给你一些顾客给出的价钱,求出邮票的组合来满足每一位顾客,要求是最多四张邮票,每张可以用多次(其实最多也就四次,因为要求最多四张,否则就是none)。
如:邮票面值1 2 3 0;0代表这行结束
顾客的需求:7 4 0
结果:
7 (3): 1 1 2 3
4 (2): 1 3
解释一下:
由于每次有多种组合,那么如何取结果呢?
如果这些组合都能满足用户的的需求,那么
1.选种类最多的
2.如果种类相同,选总数最多的
3.如果总数相同,选邮票值组合最大值最大的那一组
4.如果连最大值也相同,那么就是tie
5。如果没有这样的组合,也就是不能用4张以内的邮票满足顾客,那么就是none
输出格式,第一个是总价值,括号里面的是邮票的种类,后面是相应的值。
算法设计
做过题目的一定知道小棍(sticks)那道题目,这道和那道差不多。深搜,由于最多四张邮票,所以相当于每张邮票最多用四次,将所有情况枚举出来,对于满足用户的进行比较,取出最优的,就是结果。
输入格式就不说了。
先说一下深搜函数:
void dfs(int nn, int ssum)
{
if (ssum > m)
{
return;
}
if (ssum == m)
{
none = false;
comp();
}
if (total == 4)
{
return;
}
for (int i = nn; i < n; i ++)
{
now[total] = i;
total ++;
dfs(i, ssum + stamps[i]);
total --;
}
}
一、参数nn代表当前的邮票,ssum代表当前的邮票的总价值。
二、如果当前总价值大于客户的需求(m),那么返回
三、如果总价值==m,那么也就是说有一种方案能够满足客户要求,那么none就是false,也就是至少有一种方案,然后我会调用comp()子函数作比较
void comp() { int know = cal(now, total); int kans = cal(ans, ansnum); int maxans = getMax(ans, ansnum); int maxnow = getMax(now, total); if (ansnum == -1 || know > kans || (know == kans && ansnum > total) || (kans == know && ansnum == total && maxnow > maxans)) { tie = false; ansnum = total; for (int i = 0; i < total; i ++) { ans[i] = now[i]; } return; } if (kans == know && ansnum == total && maxnow == maxans) { tie = true; } }
1、将当前这种情况和原来的进行比较,如果种类多,或者数目多,或者最大值大,然后更新组合。否则就是tie。2、至于上面的cal函数就是计算当前有多少中邮票,getmax是获得邮票中的最大值。
四、如果一种邮票已经重复用了4次,那么也返回,应为要求最懂四张邮票,再多没用。
五、否则就从当前邮票开始,遍历每一张,每一张重复4次。
最后将ans排序输出就行了。
总的代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
int stamps[300];//保存所有邮票值
int now[5];//当前组合
int ans[5];//最终结果组合
int n,m,total,ansnum;//总邮票数目,顾客需求以及组合邮票的数目
bool tie,none;//是否是平局还是没有这种组合
bool vis[300];//为了计算多少种邮票的标志数组
int cal(int tmp[], int num)//计算有多少种类邮票
{
int res = 0;
memset(vis, 0, sizeof(vis));
for (int i = 0; i < num; i ++)
{
if (!vis[tmp[i]])
{
vis[tmp[i]] = true;
res ++;
}
}
return res;
}
int getMax(int tmp[], int num)//计算邮票中的最大值
{
int res = 0;
for (int i = 0; i < num; i ++)
{
if (res < stamps[tmp[i]])
{
res = stamps[tmp[i]];
}
}
return res;
}
void comp()//更新邮票组合
{
int know = cal(now, total);
int kans = cal(ans, ansnum);
int maxans = getMax(ans, ansnum);
int maxnow = getMax(now, total);
if (ansnum == -1 || know > kans || (know == kans && ansnum > total) || (kans == know && ansnum == total && maxnow > maxans))
{
tie = false;
ansnum = total;
for (int i = 0; i < total; i ++)
{
ans[i] = now[i];
}
return;
}
if (kans == know && ansnum == total && maxnow == maxans)
{
tie = true;
}
}
void dfs(int nn, int ssum)//深搜,遍历每一种情况
{
if (ssum > m)
{
return;
}
if (ssum == m)
{
none = false;
comp();
}
if (total == 4)
{
return;
}
for (int i = nn; i < n; i ++)
{
now[total] = i;
total ++;
dfs(i, ssum + stamps[i]);
total --;
}
}
void print()//输出格式
{
if (none)
{
printf("%d ---- none\n", m);
return;
}
printf("%d (%d):", m, cal(ans, ansnum));
if (tie)
{
printf(" tie\n");
return;
}
for (int i = 0; i < ansnum; i ++)
{
printf(" %d", stamps[ans[i]]);
}
printf("\n");
}
int main()//主函数
{
int i,j;
while (scanf("%d", &j) != EOF)
{
i = 0;
stamps[i] = j;
while (stamps[i])
{
i ++;
scanf("%d", &stamps[i]);
}
n = i ;
sort(stamps, stamps + n);
while (scanf("%d" ,&m),m)
{
total = 0;
ansnum = -1;
tie = false;
none = true;
dfs(0, 0);
if (!none)
{
sort(ans, ans + ansnum);
}
print();
}
}
return 0;
}