poj1010

来源:互联网 发布:张曼玉 知乎 编辑:程序博客网 时间:2024/05/01 04:39
STAMPS
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 12428 Accepted: 3394

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 twenty-five.

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; three different stamp types7 4 0; two customers1 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 ---- none2 (2): 1 13 (2): tie

背景真复杂。

举个例子

1 2 3 0是给你当前邮票的面值,

7 4 0这是有顾客想买,一个想买7块钱的邮票,另一个想买4块钱的邮票;

然后让你给出买邮票的方案。如果有多个方案,那么优先级如下:

1,种类最多

2,1条件相同,则个数最多

3,1,2条件相同,则最大面值大的那套方案

4,1,2,3都相同,那就是tie

5,如果没有方案就输出none

常用方法是dfs遍历所有情况,找出最优。

中间有剪枝方案就是在试过1, 1, 1, 3这种情况以后,不试1, 1, 2, 1,直接试1, 1, 2, 2,因为有1的情况已经包含在之前的遍历里面了。

想起来很好想,但是写起来我还是无从下手的感觉。于是又网上查资料,查到一位,看他的代码反反复复看了N遍,最后发现这是我学长,现在已经本科毕业工作了,再看看这还是我老乡。哈哈,这么多巧合啊!

这是他的代码:

#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;  }  

这个代码能过,但是我感觉在更新函数里面,判断句

if (ansnum==-1|| know> kans|| (know == kans&& ansnum> total)||(kans== know && ansnum == total&& maxnow> maxans))应该是ansnum<total时才更新数据,total是当前得出的,如果当前的比原来的多才会更新的。

还有就是对tie情况的处理

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和2不同,所以tie应该为false,但是如果2和3相同,tie就会被修改为true,但是tie应该是指所有的可行方案都相同才是tie,而不是局部相同。

当然了,我的代码虽说 是一步一步按照学长写的,还花了整整一天时间,可还是没过。做到最后我做不下去了。因为不懂题目中给两个1是什么意思。如果是不同种类同面值,那么2的组合就是1 1,不是tie。那么3的组合也应该是1 1 1,不是tie,因为这是两种。但是题目给出的输出显然不是这样……

我的代码:

#include <stdio.h>#include <stdlib.h>#include <string.h>int value[300], customer_value, result[4]={-1}, none_mark=0, tie_mark=1, value_num=0, now[4]={-1}, total=0, result_num = -1;bool states[300];int getkinds(int *tmp, int num){int n = 0;memset( states, 0, sizeof(states));for(int i=0; i<num; i++){if( !states[tmp[i]] ){n++;states[tmp[i]] = true;}}return n;}int getmax( int *tmp, int num){int max = 0;for(int i=0; i < num; i++){if(value[tmp[i]] > max)   max = value[tmp[i]];}return max;}void print(){if(none_mark == 1){printf("%d (%d):", customer_value, result_num);if(tie_mark == 1) printf("tie\n");else{for(int i=0; i<result_num; i++)printf(" %d", value[result[i]]);}printf("\n");}else{printf("%d ---- none\n", customer_value);}}void workout(){int result_kinds = getkinds( result, result_num);int now_kinds = getkinds(now, total);int result_max = getmax( result, result_num);int now_max = getmax(now, total);int mm = 0;if(result_num == -1)  mm = 1;if(result_num == -1 || result_kinds <now_kinds || (result_kinds == now_kinds && total > result_num) || (result_kinds == now_kinds && total && now_max > result_max) ){if( mm == 0 ) tie_mark = 0;result_num = total;for(int i=0; i<total; i++){result[i] = now[i];}}}void dfs(int nn, int stamps_sum){if(stamps_sum > customer_value) return;if(stamps_sum == customer_value){none_mark = 1;workout();}if( total == 4) return;for(int i = nn; i<=value_num; i++){now[total++] = i;dfs( i, stamps_sum + value[i]);total--;}}int main(){int i=0, tmp_value, flag=1;while(flag){while(1){if( scanf("%d", &tmp_value) == EOF) {flag = 0;break;}if(tmp_value == 0)  break;else value[i++]=tmp_value;}value_num = i-1;while(1){scanf("%d",&customer_value);if(customer_value != 0){dfs( 0 , 0 );print();}else break;}i=0;memset(result, -1, sizeof(result));none_mark = 0;tie_mark = 1;result_num = -1;total = 0;}return 0;}



原创粉丝点击