UESTC Training for Search Algorithm——I

STAMPS

Description

Have you done any Philately lately?

You have been hired by the Ruritanian Postal Service (RPS) to design their new postage software. The software allocates stamps to customers based on customer needs and the denominations that are currently in stock.

Ruritania is filled with people who correspond with stamp collectors. As a service to these people, the RPS asks that all stamp allocations have the maximum number of different types of stamps in it. In fact, the RPS has been known to issue several stamps of the same denomination in order to please customers (these count as different types, even though they are the same denomination). The maximum number of different types of stamps issued at any time is 25.

To save money, the RPS would like to issue as few duplicate stamps as possible (given the constraint that they want to issue as many different types). Further, the RPS won't sell more than four stamps at a time.

Input

The input for your program will be pairs of positive integer sequences, consisting of two lines, alternating until end-of-file. The first sequence are the available values of stamps, while the second sequence is a series of customer requests. For example:

1 2 3 0 ; three different stamp types
7 4 0 ; two customers
1 1 0 ; a new set of stamps (two of the same type)
6 2 3 0 ; three customers

Note: the comments in this example are *not* part of the data file; data files contain only integers.

Output

For each customer, you should print the "best" combination that is exactly equal to the customer's needs, with a maximum of four stamps. If no such combination exists, print "none".
The "best" combination is defined as the maximum number of different stamp types. In case of a tie, the combination with the fewest total stamps is best. If still tied, the set with the highest single-value stamp is best. If there is still a tie, print "tie".

For the sample input file, the output should be:

7 (3): 1 1 2 3
4 (2): 1 3
6 ---- none
2 (2): 1 1
3 (2): tie

That is, you should print the customer request, the number of types sold and the actual stamps. In case of no legal allocation, the line should look like it does in the example, with four hyphens after a space. In the case of a tie, still print the number of types but do not print the allocation (again, as in the example).Don't print extra blank at the end of each line.

Sample Input

1 2 3 0
7 4 0
1 1 0
6 2 3 0

Sample Output

7 (3): 1 1 2 3
4 (2): 1 3
6 ---- none
2 (2): 1 1
3 (2): tie

Source

Pacific Northwest 1998

 

/*算法思想:
  我是用的DFS,对于每一种待组合的邮票,由于最多用四张邮票组合,所以可以限制搜索的深度
  最大为4,然后要是搜索到了一种可行的解,就与ans进行判断,要是更优就覆盖ans的值,并且
  tie=false;要是出现了tie,就标记的tie值为true,搜索完之后输出,剪枝的话,不知道限制
  搜索深度为4算不算,然后我就是直接暴力了
*/

/*CODE*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int stamp[300];  //存储每种类型的邮票的面额
int type,n;  //有多少类型,待组合的邮票的面额
int ans[5],now[5];  //ans:组合情况,存储的是邮票的种类。now:每次搜索枚举是的组合情况
bool none;   //判断是不是不能组合成用户需要的邮票
bool tie;  //判断是不是tie的情况
int cal_type(int a[])  //计算这种组合方案中有多少邮票种类
{
    bool fg[300];  //用于判断这种类型的邮票是否出现在了a数组中
    int temp=0;
    memset(fg,0,sizeof(fg));
    for(int i=1;i<=a[0];i++)
        if(!fg[a[i]])
        {
            fg[a[i]]=true;
            temp++;
        }
    return temp;
}
int get_max(int a[])  //找这种组合方案中,邮票面额最大的值
{
    int temp=1;
    for(int i=2;i<=a[0];i++)
        if(stamp[a[temp]]<stamp[a[i]]) temp=i;
    return stamp[a[temp]];
}
void cmp()  //把可能的组合方案和ans进行比较,得到更优解
{
    int t1=cal_type(ans);
    int t2=cal_type(now);
    int m1=get_max(ans);
    int m2=get_max(now);
    /*不可能tie的情况*/
    if(ans[0]==-1 || t1<t2 || (t1==t2 && ans[0]>now[0]) || (t1==t2 && ans[0]==now[0] && m1<m2))
    {
        tie=false;
        for(int i=0;i<=now[0];i++)
            ans[i]=now[i];
        return;
    }
    if(t1==t2 && ans[0]==now[0] && m1==m2) tie=true;
}
void dfs(int k,int sum)  //DFS过程,当前搜索到了第k种邮票了,已经组合了sum的面额了
{
    if(sum>n) return;  //如果sum的值大于待组合的邮票的面额,退出
    if(sum==n)  //如果相等,和ans进行比较
    {
        none=false;  //不可能无解了
        cmp();  //比较
        return;
    }
    if(now[0]>=4) return;  //如果搜索的邮票数量超过了4,退出
    for(int i=k;i<type;i++)  //从上次用的邮票开始枚举判断以后的邮票
    {
        now[++now[0]]=i;
        dfs(i,sum+stamp[i]);
        --now[0];
    }
}
int main()
{
    int num;
    while(scanf("%d",&num)!=EOF)
    {
        type=0;
        stamp[type]=num;
        while(stamp[type]) scanf("%d",&stamp[++type]);  //读入所有的邮票
        sort(stamp,stamp+type);
        while(scanf("%d",&n),n!=0)
        {
            none=true;
            tie=false;
            memset(ans,0,sizeof(ans));  //初始化ans
            memset(now,0,sizeof(now));  //初始化now
            ans[0]=-1;
            now[0]=0;
            dfs(0,0);
            printf("%d ",n);
            if(none) printf("---- none");  //无解
            else
            {
                sort(ans+1,ans+1+ans[0]);
                printf("(%d):",cal_type(ans));
                if(tie) printf(" tie");  //tie
                else
                {
                    for(int i=1;i<=ans[0];i++) printf(" %d",stamp[ans[i]]);  //输出组合方案
                }
            }
            printf("\n");
        }
    }
    return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值