PKU1010解题

PKU1010
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.
假定你现在在Ruritanian邮政局工作,你的职责是设计他们的邮票软件,该软件为根据消费者的需求及库存的邮票面额来分配邮票。

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 twenty-five.
对Ruritania邮政局发行的邮票感兴趣的人超多,作为对集邮者的一种服务,RPS要求每一种分配邮票的种类数必须最多。另外,为了使消费都满意,RPS还发行一些面额相同的邮票(尽管它们的面值相同,但它们确属于不同的类别),在任何时候,一次发行的邮票种类数不超过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.
为了节省资金,RPS尽量会少发行面值相同的邮票(因为他们想尽可能多的发行邮票)。因此,他们一次最多发行4个面额相同的邮票。

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".
对于每一个客户,你应该输出符合客户需求的最好的组合,邮票种类数最大为4,如果没有这种组合存在,打印输出"none“
最好的组合是这样定义的,它应具有最大种类数的邮票。如果满足这个条件,有多种方案,那就选择邮票数量最少的方案,如果还有多种方案,那就选择最大面额最高的一种方案,如果还有多种方案,那没辙了,输出“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.
这也就是说,你应该把客户的需求打印出来,邮票种类数以及实际的邮票,如果没有合适的分配,像第二行输出的那样,输出四个‘-’,如果是个死结的话,那就输出“tie",像最后一行那样

Sample Input

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

Sample Output

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

从上午开始做,弄清了题意,又在网上看了网友的解法,大致清楚了解题过程,下午开始编程,在对数据的组合上花费了很多时间,到晚上终于把程序写完了,提交,AC了,哈哈。

这道题并非是很难的题,如果在第一步就过去的话,后面的便很容易了处理了。难在哪里呢,难在如何将一堆数进行组合,题目中已经说明了,一次最多只卖 4张邮票,这什么意思呢?也就是说只有5种选择,一种是0张,1张,2张,3张,4张,这样,我们可以定义一个大小为4的数组,数组存放邮票的序号,相同的序号代表是同一种邮票,不同的序号代表是不同的邮票,我们可以根据数组的内容来记录当前邮票的种类数,邮票的张数,还有最大面值值。

而后,再定义一个上限为25的数组stamps[MAX],来存放邮票的面值,并使用变量stamp_total来记录输入的邮票的种类数,这里要注意了,在将邮票面值插入到stamps末尾时,一定要判断待插入邮票的面值是否已经在stamps里存在超过或等于4次,若超过或等于4次,那也就不用插入了。

下面便是关键的一步了,我们要找到满足客户需求的邮票组合,显然邮票数组stamps的邮票序号分别是0,1,2,3.。。。我们将从中选取4个序号(序号可相同),如果这4个序号代表的邮票面值和等于客户需求值,说明这一组邮票为候选组,对该候选组进行处理即可。

对候选组取其邮票的种类数a1,邮票的张数b1,以及最大面值c1,继续搜索,寻找下一个候选组,求其邮票的种类数a2,邮票张数b2,最大面值 c2,用题目中给出的条件对a1与a2,b1与b2,c1与c2进行比较,并对候选组进行更新处理。

附上AC后的源代码:

Source Code
Problem: 1010        User: PJYang
Memory: 692K        Time: 0MS
Language: G++        Result: Accepted

    * Source Code

      #include<iostream>
      using namespace std;

      #define MAX 100
      int stamps[MAX],temp[4],result[4];//stamps数组是输入的邮票,temp是临时存储候选邮票组的序号,result代表是最终选取的候选邮票组
      int request,stamp_total,max_stamps_class,min_stamps,max_stamp_value;//request代表是客户提供的金额,//stamp_total代表是输入的邮票总数,max_stamps_class代表是候选邮票的种类数,min_stamps代表是候选邮票的张数, //max_stamp_value代表是最大邮票面值
      bool istie; //是否是死结

    //求候选组的邮票种类数
      int get_total_class()
      {
          int total=0;
          if(temp[3]!=(stamp_total-1))
              total++;
          if(temp[2]<temp[3])
              total++;
          if(temp[1]<temp[2])
              total++;
          if(temp[0]<temp[1])
              total++;

          return total;
      }

      //求候选邮票的张数
      int get_total_stamps()
      {
          int total=0;
          for(int i=0;i<4;i++)
              if(stamps[temp[i]]!=0)
                  total++;
          return total;
      }

      //求候选邮票的最大面值
      int max_value()
      {
          int max=stamps[temp[0]];
          for(int i=1;i<4;i++)
              if(stamps[temp[i]]>max)
                  max=stamps[temp[i]];
          return max;
      }

      //输入判断,同种面值的邮票不允许超过4种
      bool lessthan5(int _temp)
      {
          int i,total=0;
          for(i=0;i<stamp_total;i++)
              if(stamps[i]==_temp)
                  total++;
          return total<5;
      }

      //对变量进行初始化
      void init_result()
      {
          for(int i=0;i<4;i++)
          {
              temp[i]=0;
              result[i]=0;
          }

          istie=true;
          max_stamps_class=0;
          min_stamps=5;
          max_stamp_value=0;
      }

      void value_result()
      {
          for(int i=0;i<4;i++)
              result[i]=temp[i];
      }

       //处理过程
      void start_deal()
      {
          int i,j,k,l;
          for(i=0;i<stamp_total;i++)
              for(j=i;j<stamp_total;j++)
                  for(k=j;k<stamp_total;k++)
                      for(l=k;l<stamp_total;l++)
                      {
                          temp[0]=i;
                          temp[1]=j;
                          temp[2]=k;
                          temp[3]=l;
                         
                          if(stamps[i]+stamps[j]+stamps[k]+stamps[l]==request)
                          {
                              int _max_stamps_class=get_total_class();
                              int _min_stamps=get_total_stamps();
                              int _max_value=max_value();

                              if(_max_stamps_class>max_stamps_class)
                              {
                                  istie=false;
                                  max_stamps_class=_max_stamps_class;
                                  min_stamps=_min_stamps;
                                  max_stamp_value=_max_value;
                                  value_result();
                                  continue;
                              }
                              else if(_max_stamps_class==max_stamps_class)
                              {
                                  if(_min_stamps<min_stamps)
                                  {
                                      istie=false;
                                      min_stamps=_min_stamps;
                                      max_stamp_value=_max_value;
                                      value_result();
                                      continue;
                                  }
                                  else if(_min_stamps==min_stamps)
                                  {
                                      if(_max_value>max_stamp_value)
                                      {
                                          istie=false;
                                          value_result();
                                          max_stamp_value=_max_value;
                                          continue;
                                      }
                                      else if(_max_value==max_stamp_value)
                                      {                           
                                          istie=true;
                                      }
                                  }
                              }
                          }
                      }
      }

       //输出结果
      void print()
      {
          if(max_stamps_class==0)
          {
              cout<<request<<" ---- none"<<endl;
              return;
          }

          cout<<request<<" ("<<max_stamps_class<<"):";

          if(istie)
          {
              cout<<" tie"<<endl;
              return;
          }

          for(int i=0;i<4;i++)
              if(stamps[result[i]]!=0)
                  cout<<" "<<stamps[result[i]];
          cout<<endl;

      }
      int main()
      {
          int stamp_input;
    //输入邮票
          while(cin>>stamp_input)
          {
              stamps[0]=stamp_input;
              stamp_total=1;

              while(cin>>stamp_input)
              {
                  if(lessthan5(stamp_input))
                  {
                      stamps[stamp_total]=stamp_input;
                      stamp_total++;
                  }

                  if(stamp_input==0) break;
              }
             
        //处理,显示结果
              while(cin>>request,request)
              {
                  init_result();
                  start_deal();   
                  print();
              }
          }
          return 0;
      }





其实,以上代码对于匹配邮票对的搜索稍嫌粗糙,写4个for循环不算什么,但如果题目要求改变了,莫非你愿意去写20个for循环?我在网上看到一种更好的方法,不过才疏学浅,看了一个下午也没有看懂,虽然只有短短的几句话:

int s[6];
void solve(int deep,int n)
{
      if(deep == 5)
      {
        cout<<s[1]<<" "<<s[2]<<" "<<s[3]<<" "<<s[4]<<endl;
        return;
    }
      for(int i = s[deep-1];i <= n; i++)
      {
            s[deep]=i;
            solve(deep+1,n);
      }
}

int main()
{
    int temp;
    while(cin>>temp)
    {
        solve(1,temp);
    }
}

嘻嘻,大家可以试运行下,相信一看结果就明白实现的是什么功能了,如果将这一段代码移植到我的程序中,显然瘦身不少,另外,我的程序是没有经过优化的,若加以优化,又可以砍掉不少。Oh Yeah! 时间不早了,不写了,明天开始主攻PKU 1011了。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值