poj1010-STAMPS

题目大意

给你一些邮票的面值,然后给你一些顾客给出的价钱,求出邮票的组合来满足每一位顾客,要求是最多四张邮票,每张可以用多次(其实最多也就四次,因为要求最多四张,否则就是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;
}


 

 

你可能感兴趣的:(算法)