题目实在是太难懂了,我翻译了一下。。。
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 twenty-five.
浪漫国充满了集邮的人。作为对这些人的服务,浪漫国邮政服务要求所有的邮票分配不同类型的邮票种类以及它的最大数目。事实上,RPS还发行以一些面额相同的邮票来取悦客户(这些算不同的类型,即使它们是相同的面额)发行的不同邮票的种类的最大数目是二十五。
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.
输入的程序将是正整数序列,由两行组成,交替直到文件结束。
第一行是邮票的价值。而第二行是一系列的客户要求。(注:第一行数字是邮票的面值,每一个数字就是一个不同的种类,哪怕面值相同。以0结束。第二行数字是顾客所需要的邮票总面值。每个数字就是一个顾客的需求,以0结束。)
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”.
对于每一个顾客,你应该输出最好的组合(完全等同于客户的要求的组合),最多4张邮票。如果不存在这样的组合,输出“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”.
“最佳”组合被定义为不同类型的标记类型的最大数目。在平局的情况下,用最少的总邮票的组合是最好的。如果还平局着,有最高的单值邮票是最好的。如果还平局,输出“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 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
题目还是比较难懂。。。
解释一下:
由于每次有多种组合,那么如何取结果呢?
如果这些组合都能满足用户的的需求,那么
1.选种类最多的
2.如果种类相同,选总数最多的
3.如果总数相同,选邮票值组合最大值最大的那一组
4.如果连最大值也相同,那么就是tie
5。如果没有这样的组合,也就是不能用4张以内的邮票满足顾客,那么就是none
输出格式,第一个是总价值,括号里面的是邮票的种类,后面是相应的值。
(摘自http://blog.csdn.net/zhang20072844/article/details/6685353)
思路:DFS +剪枝 自己写了个传5个值的DFS,回溯出了点儿问题
剪枝:1.不能选超过4张邮票(显然的剪枝)
2.把邮票按升序排序,从小到大选(因为种类越多越好,邮票面值小的时候,选的种类肯定是要多一点儿的)
(写了挺长时间,,特别容易在回溯的时候出错)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int alen,blen,a[66],b[66],jy,jyy[66],vis[66];
bool tied,printed;
void dfs(int max_kind,int min_num,int max_money,int x,int pre)
{
if(min_num>4) return;//不能选四张以上的邮票
if(x==jy)//和b[i]的值相等
{
if(max_kind>jyy[alen+1])//jyy[alen+1]表示kind的最大值
{
tied=false;//如果有新的解,要把tied赋值成false
for(int i=1;i<=alen;i++)
jyy[i]=vis[i];
jyy[alen+1]=max_kind;
jyy[alen+2]=min_num;
jyy[alen+3]=max_money;
}
else if(max_kind==jyy[alen+1])
{
if(min_num<jyy[alen+2])//jyy[alen+2]表示num的最小值
{
for(int i=1;i<=alen;i++)
jyy[i]=vis[i];
jyy[alen+2]=min_num;
jyy[alen+3]=max_money;
tied=false;
}
else if(min_num==jyy[alen+2])
{
if(max_money>jyy[alen+3])////jyy[alen+3]表示money的最大值
{
for(int i=1;i<=alen;i++)
jyy[i]=vis[i];
jyy[alen+3]=max_money;
tied=false;
}
else if(max_money==jyy[alen+3])
tied=true;
}
}
}
int temp;
for(int i=pre;i<=alen;i++)//i从pre开始,(技巧剪枝)
{
if(vis[i]<=4)
{
if(!vis[i])max_kind++;//多少种
vis[i]+=1;
if(max_money<=a[i])
{
max_money=a[i];
temp=max_money;
}
dfs(max_kind,min_num+1,max_money,x+a[i],i);
vis[i]=vis[i]-1;
if(vis[i]==0)
{
max_kind--;
if(a[i]==max_money)
{
a[i]=temp;
}
}
}
}
}
int main()
{
scanf("%d",&a[1]);//比较坑的循环方式
start:
tied=false;
for(int i=2;;i++)//读入 不解释
{
scanf("%d",&a[i]);
if(a[i]==0)
{
alen=i-1;
break;
}
}
sort(a+1,a+1+alen);//从小到大排序,为了剪枝
for(int i=1;;i++)
{
scanf("%d",&b[i]);
if(b[i]==0)
{
blen=i-1;
break;
}
}
for(int i=1;i<=blen;i++)
{
tied=printed=0;
jyy[alen+2]=0x3f3f3f3f;//num是选最小值的,所以赋值成极大值
memset(vis,0,sizeof(vis));
memset(jyy,0,sizeof(jyy));
jy=b[i];
dfs(0,0,0,0,1);//pre要从1开始
if(tied) printf("%d (%d): tie
",jy,jyy[alen+1]);
else
{
for(int i=1;i<=alen;i++)
if(jyy[i]!=0) printed=true;
if(!printed)
printf("%d ---- none
",jy);
else
{
printf("%d (%d): ",jy,jyy[alen+1]);
for(int i=1;i<=alen;i++)
{
for(int j=1;j<=jyy[i];j++)
{
if(i==alen&&j==jyy[i])printf("%d",a[i]);
else printf("%d ",a[i]);
}
}
printf("
");
}
}
}
if(scanf("%d",&a[1])!=EOF) goto start;//循环回前面。
}