1010 STAMPS

STAMPS
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 10034   Accepted: 2661

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 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

Source

Pacific Northwest 1998
/* 问题重述: 给出n种邮票,每种邮票有自己的面值(面值可能重复) 指定m种“总面值”,对每种“总面值”,求解满足如下条件的组合以达到该“总面值” (1)所用邮票在n种中可以重复选取 (2)所用邮票张数〈=4 (3)尽量多的使用那个不同种类的邮票 Max (Stamp Types) (4)若有多种方案满足(3),则选取张数最小的一种方案 Min (Stamp Num) (5)若有多种方案满足(3)(4),则选取“最大面额”最高的一种方案。 Max(Heightest Value) (6)若有多种方案满足(3)(4)(5) 则输出 “tie” 题目分析: (1)算法定位: 从题目的条件可知,此题必须遍求所有方案以求解,因此采用搜索的方法是非常合理的,因为题目带由一定的递推性,也可以尝试动态规划的方法. (2)问题优化与简化 对于搜索型题目,关键的优化就是减少重复计算,本题可由3方面的简化,避免重复性计算. (1)对于面额相等的邮票,可以限制在1~5张,多余的可以不处理,例如这样的输入: 1 1 1 1 1 1 1 1 0 8个1 4 0 可以简化成为: 1 1 1 1 1 0 5个1 4 0 他们的解是相同的 (2)搜索求解时约定, 后一张邮票面额>=前面张邮票的面额,即如下的6种情况: 1 2 3 2 3 1 3 12 1 3 2 3 2 1 2 1 3 只需搜索判断一种,即 1 2 3 的情况 (3)对于给定的n种邮票,遍历4张邮票的所有可达“总面额”的解,当m种指定面额给出,只需插标输出即可,不需要重复m次类似的搜索。(因为m次的搜索中,很多是重复计算的) 搜索方法一:主要思路: 4重循环,枚举所有可能,依据题目条件保留最优解。 For(i=1;i<=total_stamps;i++) For(j=i;j<=total_stamps;j++) For(k=j;k<=total_stamps;k++) For(l=k;l<=total_stamps;l++) { 更新最优解 } 优化: 使用优化方案(1)(2), 修改后可以加上优化方案(3) 评价: 编程复杂度低,代码少,运行时空效率高,比赛时候推荐使用 但是扩展性受限制,若题目给的是任一k张而不是4,则必须大量修改代码 */ #include<cstdio> int num;//邮票种树,1.....num int stamp[120];//题目说的25,应该不止 int curs;//最好的情况下,邮票种类的数目 int curn;//最好的情况下,邮票的张数 int rmax;//最好的情况下,最大面值邮票的面值 int f;//记录所有的种类,会不会是tie int now[4]; bool ok(int x) { int sum=0; for(int i=1; i<=num; i++) if(stamp[i]==x) sum++; if(sum>=4) return 0; else return 1; } void cal(int x) { int zs,zn;//暂时种类的数目和张数 for(int i=0; i<=num; i++) for(int j=i; j<=num; j++) for(int k=j; k<=num; k++) for(int l=k; l<=num; l++) { if(stamp[i]+stamp[j]+stamp[k]+stamp[l]!=x) continue;//连面值都没达到,当然退出 zs=4; zn=4; if(i==0) zs--,zn--; if(i==j) zs--; if(j==0) zn--; if(j==k) zs--; if(k==0) zn--; if(k==l) zs--;//有一种一样,就减去一种 if(l==0) zn--; int rrmax=-1; if(stamp[i]>rrmax) rrmax=stamp[i]; if(stamp[j]>rrmax) rrmax=stamp[j]; if(stamp[k]>rrmax) rrmax=stamp[k]; if(stamp[l]>rrmax) rrmax=stamp[l]; if(zs>curs)//现在这种方案的种类多 { f=0; curs=zs; curn=zn; rmax=rrmax; now[0]=stamp[i],now[1]=stamp[j],now[2]=stamp[k],now[3]=stamp[l]; } else if(zs==curs) { if(zn<curn) { f=0; curn=zn; rmax=rrmax; now[0]=stamp[i],now[1]=stamp[j],now[2]=stamp[k],now[3]=stamp[l]; } else if(zn==curn) { if(rrmax>rmax) { f=0; rmax=rrmax; now[0]=stamp[i],now[1]=stamp[j],now[2]=stamp[k],now[3]=stamp[l]; } else if(rrmax==rmax) { f++; } } } } if(f==-1) printf("%d ---- none/n",x); else if(f>=1) printf("%d (%d): tie/n",x,curs); else { printf("%d (%d):",x,curs); for(int i=0;i<4;i++) if(now[i]!=0) printf(" %d",now[i]); printf("/n"); } } int main() { int x; while(scanf("%d",&x)!=EOF) { num=0; stamp[0]=0;//第0种邮票面值当然为0 stamp[++num]=x; while(scanf("%d",&x)!=EOF) { if(x==0) break; if(ok(x)) { stamp[++num]=x; } } while(scanf("%d",&x)!=EOF) { if(x==0) break; curs=0; curn=0; f=-1; rmax=-1; cal(x); } } return 0; }
深度搜索
/* 搜索方法二: (base on hawking’s program) 主要思路: 递归深度搜索,遍历所有k张邮票的可达面额的解,保留每种面额的最优 解,查表输出指定面额的解,并给定k=4,即为题目要求的情况。 Void Solve(int deep) { 更新当前方案所达面值的最优解 if (deep>4) return; for(int s=now[deep-1];s<=total_stamp;s++) { now[deep]=s; solve(deep+1); } } 优化: 使用优化方案(1)(2)(3)进行截枝 评价: 深度搜索的经典模板程序,推荐学习,几乎所有的搜索都可以套用的模板 编程复杂度中,运行时空效率高,通用性强一些,但代码可能稍为多一些 */ #include<cstdio> int stamp[120]; int num; int curs; int curn; int rmax; int zs,zn; int f; int x,rrmax; int now[4]; int wat[4]; bool ok(int x) { int sum=0; for(int i=1; i<=num; i++) if(stamp[i]==x) sum++; if(sum>=4) return 0; else return 1; } void dfs(int k,int step,int sum) { if(step>=4) { if(sum!=x) return;//连面值都没达到,当然退出 if(zs>curs)//现在这种方案的种类多 { f=0; curs=zs; curn=zn; rmax=rrmax; wat[0]=now[0],wat[1]=now[1],wat[2]=now[2],wat[3]=now[3]; } else if(zs==curs) { if(zn<curn) { f=0; curn=zn; rmax=rrmax; wat[0]=now[0],wat[1]=now[1],wat[2]=now[2],wat[3]=now[3]; } else if(zn==curn) { if(rrmax>rmax) { f=0; rmax=rrmax; wat[0]=now[0],wat[1]=now[1],wat[2]=now[2],wat[3]=now[3]; } else if(rrmax==rmax) { f++; } } } return ; } for(int i=k; i<=num; i++) { if(i==0) zn--;//张数少一张 if(i==k) zs--;//种类少一种 int tt=rrmax;//用来恢复现场的 now[step]=stamp[i]; if(stamp[i]>rrmax) rrmax=stamp[i]; dfs(i,step+1,sum+stamp[i]); rrmax=tt; if(i==0) zn++; if(i==k) zs++; } } int main() { while(scanf("%d",&x)!=EOF) { num=0; stamp[0]=0; stamp[++num]=x; while(scanf("%d",&x)!=EOF) { if(x==0) break; if(ok(x)) stamp[++num]=x; } while(scanf("%d",&x)!=EOF) { if(x==0) break; curs=0; curn=0; rmax=-1; rrmax=-1; f=-1; zs=4; zn=4; now[0]=now[1]=now[2]=now[3]=0; wat[0]=wat[1]=wat[2]=wat[3]=0; dfs(0,0,0); if(f==-1) printf("%d ---- none/n",x); else if(f>=1) printf("%d (%d): tie/n",x,curs); else { printf("%d (%d):",x,curs); for(int i=0; i<4; i++) if(wat[i]!=0) printf(" %d",wat[i]); printf("/n"); } } } return 0; }

你可能感兴趣的:(优化,service,input,output,Allocation,Types)