poj1010 dfs/枚举

题意:
给出不同类型的一组邮票,不同类型的邮票面值可能相同。求符合用户输入面值,且最多取4张邮票的最佳方案。最佳方案满足以下要求:
类型数最多。
如果类型数相同,则张数少者。
如果张数也相同,则单张面值最大者。
如果以上都相同,则无最佳方案(平局)。
如果不能达到用户的输入面值,则输出none。

难度:**

算法:
1.dfs

2.暴搜(枚举)


/*
dfs:注意剪枝 
*/ 
#include<stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <map> 
using namespace std;

int stamp_val[100];			// stamp_val[i]=j:第i类邮票的面额是j 
int request[100];			// request[i]=j:第i位顾客的需求是j 
int best_ans[5];			// 记录最佳答案 
int curr_ans[5];			// 记录当前答案 
bool visited[100];			// 访问标志 
 	
int max_types;				// 最大类型数 
int min_stamp_num;			// 最少张数 
int highest_val;			// 最大面额 
bool isTie;					// tie标志 
int stamp_num;				// 邮票总数, stamp_val数组的长度 


// 更新最优解 
void updateBest()
{
	for (int i=1; i<=4; i++)
	{
		best_ans[i] = curr_ans[i];
	}
}

/*
curr_stamp_num:当前的邮票张数
curr_types:当前的邮票类型数
curr_highest:当前的最大面额
start:从第start个类型的邮票开始搜索
curr:当前已选所有邮票的总面额
request:客户输入的面额 
*/
void dfs(int curr_stamp_num,int curr_types,int curr_highest,int start,int curr,int request)
{
	// 判断是否出现了最优解 
	if (curr == request)
	{
		if (max_types < curr_types)
		{
			max_types = curr_types;
			min_stamp_num = curr_stamp_num;
			highest_val = curr_highest;
			isTie=false;
			updateBest();
		}
		else if (max_types == curr_types)
		{
			if (min_stamp_num >  curr_stamp_num)
			{
				min_stamp_num = curr_stamp_num;
				highest_val = curr_highest;
				isTie=false;
				updateBest();
			}
			else if (min_stamp_num ==  curr_stamp_num)
			{
				if (highest_val < curr_highest)
				{
					highest_val = curr_highest;
					isTie=false;
					updateBest();
				}
				else if (highest_val == curr_highest)
				{
					isTie = true;
				}
			}
		}
		return ;
	}
	// 已四张,返回 
	if (curr_stamp_num == 4)
	{
		return;
	}
	/*
	此处为何从start而不是0开始搜索?
	1.避免重复,如 1 1 2 同 1 2 1在数值上是相同的
	2.更重要的是:从0开始是错误的!
	  回溯结束时,节点i被置为false,那么搜索i+1时如果仍从0开始搜索,会误认为i未访问过,因此,类型数会误加1 
	*/
	for (int i=start; i<stamp_num; i++)
	{
		if (stamp_val[i] >0 && curr+stamp_val[i] <= request)
		{
			curr_ans[curr_stamp_num+1]=stamp_val[i];
			if (visited[i])
			{
				visited[i] = true;
				dfs(curr_stamp_num+1,curr_types,stamp_val[i],i,curr+stamp_val[i],request);
			}
			else
			{
				visited[i] = true;
				dfs(curr_stamp_num+1,curr_types+1,stamp_val[i],i,curr+stamp_val[i],request);
			}
			visited[i] = false;
			curr_ans[curr_stamp_num+1]=0;
		}
	}
}


int main()
{
	int tmp;
	while (scanf("%d",&tmp)!=EOF)
	{
		int stamp_value;
		stamp_num = 1;
		int req;
		int customer_num = 0;
		memset(stamp_val,0,sizeof(int));
		memset(request,0,sizeof(int));
		memset(best_ans,0,sizeof(int));
		memset(curr_ans,0,sizeof(int));
		memset(visited,false,sizeof(bool));
		
		stamp_val[0] = tmp;
		while (scanf("%d",&stamp_value))
		{
			if (stamp_value == 0)
			{
				break;
			}
			stamp_val[stamp_num++] = stamp_value;
		}
		while(scanf("%d",&req))
		{
			if (req == 0)
			{
				break;
			}
			request[customer_num++] = req;
		}
		sort(stamp_val,stamp_val+stamp_num);
	
		for (int i=0; i<customer_num; i++)
		{
			max_types = 0;
			isTie = false;
			min_stamp_num = 0;
			if (stamp_val[stamp_num-1]*4 >= request[i] && stamp_val[0] <= request[i])
			{
				dfs(0,0,0,0,0,request[i]);
			}
			printf("%d ",request[i]);
			if (max_types == 0)
			{
				printf("---- none\n");
			}
			else if (isTie)
			{
				printf("(%d): tie\n",max_types);
			}
			else 
			{
				sort(best_ans,best_ans+5);
				printf("(%d):",max_types);
				for (int j=1; j<=4; j++)
				{
					if (best_ans[j] == 0)
					{
						continue;
					}
					printf(" %d",best_ans[j]);
				}
				printf("\n");
			}
		}
	}
}


/*
枚举/暴搜:注意剪枝,如果面值相同的邮票超过5枚,其它的"剪掉" 
*/ 

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std; 

int cmp(const void* a,const void* b)
{
    return (int*)a - (int*)b;
} 

struct ANS
{
    int types;
    int num ;
    int max_value ;
    int stamps[30];
}; 


int stamps[100];
int request[100];

// 获取类型数 
int get_types(int a, int b, int c, int d)
{
    map<int,int> mp;
    mp[a]++;
    mp[b]++;
    mp[c]++;
    mp[d]++;
    mp.erase(0);
    return mp.size();
}

int main()
{
    int tmp;
    while (scanf("%d",&tmp)!=EOF)
    {
    	int stamp_num,req,stamp_value ;
    	int customer_num = 1;
    	memset(stamps,0,sizeof(stamps));
    	memset(request,0,sizeof(request));
    	stamps[1] = tmp;
    	stamp_num = 2;
    	
    	map<int,int> mp;
    	mp[tmp]++;
	    while(scanf("%d",&stamp_value))
	    {
	        if (stamp_value == 0)
	        {
	            break; 
	        } 
	        mp[stamp_value]++;
	        // if the number of the stamps which have the same value is more than 5,then do not put it into stamps arrays. 
	        if (mp[stamp_value] < 6)
	        {
	        	stamps[stamp_num++] = stamp_value;
	        }
	    }
	    while(scanf("%d",&req))
	    {
	        if (req == 0)
	        {
	            break;
	        }
	        request[customer_num++] = req;
	    }
	    qsort(stamps,stamp_num,sizeof(int),cmp);
	   
	    // for each person
	    int curr;
	    for (int i=1; i<customer_num; i++)
	    {
	        // curr = 0;
	        ANS tmp_ans;
	        ANS best_ans = {0,0,0,{0,0,0,0,0}};                    
	        bool tier = false;
	        // the fist stamp
	        for (int j=0; j<stamp_num; j++)
	        {
	            // the second stamp
	            for (int k=j; k<stamp_num; k++)
	            {
	                // the third stamp
	                for (int l=k; l<stamp_num; l++)
	                {
	                    // the forth stamp
	                    for (int m=l; m<stamp_num; m++)
	                    {
	                        curr = stamps[j] + stamps[k] + stamps[l] + stamps[m];
	                        if (curr > request[i])
	                        {
	                        	break;
	                        }
	                        else if (curr == request[i])
	                        {
	                            tmp_ans.max_value =  max(max(stamps[j],stamps[k]),max(stamps[l],stamps[m]));
	                            tmp_ans.types = get_types(j,k,l,m);
	
	                            int cnt=1;
	                            if (stamps[j] != 0)
	                            {
	                                tmp_ans.stamps[cnt++] = stamps[j];
	                            }    
	                            if (stamps[k] != 0)
	                            {
	                                tmp_ans.stamps[cnt++] = stamps[k];
	                            }
	                            if (stamps[l] != 0)
	                            {
	                                tmp_ans.stamps[cnt++] = stamps[l];
	                            }
	                            if (stamps[m] != 0)
	                            {
	                                tmp_ans.stamps[cnt++] = stamps[m];
	                            }
	                            tmp_ans.num = cnt-1;    
	                            
								// compare the tmp answer with the current best answer
	                            bool flag = false;
	                            if (tmp_ans.types > best_ans.types)
	                            {
	                                flag = true;
	                                tier = false;
	                            }            
	                            else if (tmp_ans.types == best_ans.types)
	                            {
	                                if (tmp_ans.num < best_ans.num)
	                                {
	                                    flag = true;
	                                    tier = false;
	                                }
	                                else if (tmp_ans.num == best_ans.num)
	                                {
	                                    if (tmp_ans.max_value > best_ans.max_value)
	                                    {
	                                        flag = true;
	                                        tier = false;
	                                    }
	                                    else if (tmp_ans.max_value == best_ans.max_value)
	                                    {
	                                        tier = true;
	                                    }
	                                }
	                            }
	                            
	                            // update the best answer
	                            if (flag)
	                            {
	                                best_ans.num = tmp_ans.num;
	                                best_ans.types = tmp_ans.types;
	                                best_ans.max_value = tmp_ans.max_value;
	                                for (int ii=1; ii<=best_ans.num; ii++)
	                                {
	                                    best_ans.stamps[ii] = tmp_ans.stamps[ii];
	                                }
	                            }
	                        }
	                    }
	                }
	            }
	        }
	        // output the answer
	        printf("%d ",request[i]);
	        if (best_ans.num == 0)
	        {
	            printf("---- none\n");
	        }
	        else if (tier)
	        {
	            printf("(%d): tie\n",best_ans.types);
	        }
	        else 
	        {
	            sort(best_ans.stamps,best_ans.stamps+5);
	            printf("(%d):",best_ans.types);
	            for (int j=1; j<=4; j++)
	            {
	                if (best_ans.stamps[j] == 0)
	                {
	                    continue;
	                }
	                printf(" %d",best_ans.stamps[j]);
	            }
	            printf("\n");
	        }
	    }
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kangwq2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值