poj 1010 邮票问题 DFS
来源:互联网 发布:js onmousemove 编辑:程序博客网 时间:2024/06/04 19:58
原文地址:http://hi.baidu.com/you289065406/blog/item/8c4395033c085d0b738b6502.html
大致题意:
题意比较难懂。大致如下:
第一行数字是邮票的面值,每一个数字就是一个不同的种类,哪怕面值相同。以0结束。
第二行数字是顾客所需要的邮票总面值。每个数字就是一个顾客的需求,以0结束。
每两行是一组case。以EOF结束输入。
顾客是集邮爱好者,所以你必须尽可能的给他不同种类的邮票。
但是一位顾客最多只能拿4张邮票。
显然,我们拥有的邮票就是第一行中的数据。
解题思路:
DFS寻找所有的解,再逐一比较寻找最优解,剪枝是关键。
关于tie。
满足顾客需求的解就是可行解。
邮票种类最多的可行解为最优。
如果存在两个以上的最优解的邮票种类是一样的,张数最少的更优
张数也一样的话,这些最优解中最大面值较大的更优。
若邮票种类、张数、最大面值三者都分别相同,则认为这些最优解相同,输出tie。
没有解就是none。
做法大致有三种。
可以去参考这位牛人的三种方法:http://blog.csdn.net/cugbliang/article/details/2742242
1、枚举。反正最多拿4张,可以4重循环暴搜最优解。
2、DFS。每次搜索后,如果有解,更新最优解,关键在剪枝。
3、三维DP。这个没怎么研究,不太懂……参考上面的网址吧。。
我用的是第二种DFS
剪枝:
1、最多拿四张邮票,如果同一面值的邮票种类超过5,以5计算。
为什么不以4计算呢?因为tie
2、若DFS的深度超过了4,那么就返回。(最多四张邮票)
3、技巧剪枝:
先对输入的邮票按面值升序排序,DFS到面值k时,不再搜索面值<k的邮票。
同时排序也是为了保证DFS的最优解的邮票种类最多。
#include<iostream>#include<algorithm>using namespace std;const int size=26;int value[size];//第i种邮票的面值value[i]int pv;//value的指针int tim[size];//标记第i种邮票被分配过的次数bool flag;//标记是否已经出现过解bool flag_tie;//标记是否为tieint solve[6];// solve[0]:邮票张数 ,solve[5]邮票的种数 solv[1...4]持有的面值,0代表不持有int bestsolve[6];//最优解int max4(int *s){ int a=s[1]>s[2]?s[1]:s[2]; int b=s[3]>s[4]?s[3]:s[4]; return a>b?a:b;}void best(int num,int type){ bestsolve[0]=num; bestsolve[5]=type; for(int k=1;k<=4;k++) bestsolve[k]=solve[k]; return;}void dfs(int need,int num,int type,int pre) //need:总面值 num:邮票张数 type:邮票种数 pre:当前面值 { if(num==5) return;//剪枝,顾客持有邮票张数不超过4 if(need==0) { if(!flag) { if(type==bestsolve[5])//最优解的种类type相同 { if(num==bestsolve[0])//最优解的张数相同 { int maxs=max4(solve);//solve的最大面值 int maxbs=max4(bestsolve);//bestsolve的最大面值 if(maxs==maxbs)//存在多个最优解 flag_tie=true; else if(maxs>maxbs)//种类和张数都相同的情况下,最大面值较大者优先 { flag_tie==false; best(num,type); } } else if(num<bestsolve[0])//种类相同的情况下,张数少的优先 { flag_tie=false; best(num,type); } } else if(type>bestsolve[5])//种类多的解优先 { flag_tie=false; best(num,type); } } else { flag=true; best(num,type); } return ; } for(int i=0;i<pv;i++) { if(i<pre)//剪枝,不重复搜索比当前面值小的邮票,同时避免错误的tie continue; if(need>=value[i]) { solve[num+1]=value[i]; if(tim[i]!=0) { tim[i]++; dfs(need-value[i],num+1,type,i); } else { tim[i]++; dfs(need-value[i],num+1,type+1,i); } solve[num+1]=0;//回溯 tim[i]--; } else return;//value已排序 } return;}int main(){ while(true) { pv=0; int type[size]={0};//面值为i的邮票的种数type[i] int tmp; while(1) { if(scanf("%d",&tmp)==EOF)//写在循环条件里怎么就TLE呢 exit(0); //这两句注释掉 机器就跑不出来。。。 if(tmp==0) break; if(type[tmp]<5)//剪枝,如果一样的面值出现5次一上那么以后的就不要记录 { type[tmp]++; value[pv++]=tmp; } } sort(value,value+pv);//要使分配的邮票的种类尽可能多 //只需在搜索前把邮票面值升序排序,从最小面值开始搜索 int need; while(scanf("%d",&need)!=EOF&&need) { flag=false; flag_tie=false; memset(solve,0,sizeof(solve)); memset(bestsolve,0,sizeof(bestsolve)); memset(tim,0,sizeof(tim)); dfs(need,0,0,0); cout<<need; //printf("%d",need); if(bestsolve[0]==0) cout<<" ---- none"<<endl; else { cout<<" ("<<bestsolve[5]<<"):"; if(flag_tie) cout<<" tie"<<endl; else { sort(bestsolve+1,bestsolve+5); for(int i=1;i<=4;i++) { if(bestsolve[i]==0) continue; cout<<" "<<bestsolve[i]; } cout<<endl; } } } } return 0;}
下面是本菜鸟,照葫芦画飘弄的。。。
#include<iostream>#include<algorithm>#define size 26using namespace std;int value[size];int type[size];int tim[size];int solve[6];int bestsolve[6];bool flag,flag_tie;int need;int pv;int maxs(int *s)//找最大的面值 { int a,b; a=s[1]>s[2]?s[1]:s[2]; b=s[3]>s[4]?s[3]:s[4]; return a>b?a:b;}void best(int num,int type)//更新最优解 { bestsolve[0]=num; bestsolve[5]=type; for(int k=1;k<=4;k++) bestsolve[k]=solve[k];}void dfs(int need,int num,int type,int pre){ if(num==5) return; //printf("%d %d %d %d \n",need,num,type,pre); //system("pause"); if(need==0)//如果搜到了一种情况,进行判断 { if(!flag) { if(type==bestsolve[5]) { if(num==bestsolve[0]) { int max1=maxs(solve); int max2=maxs(bestsolve); if(max1==max2) { flag_tie=true; best(num,type); } else if(max1>max2) best(num,type); } else if(num<bestsolve[0]) { flag_tie=false; best(num,type); } } else if(type>bestsolve[5]) { flag_tie=false; best(num,type); } } else { flag=true; best(num,type); } return; } for(int i=0;i<pv;i++) { if(i<pre) continue;//搜比它大的面值 //printf("i=%d\n",i); if(need>=value[i]) { if(tim[i]!=0) { tim[i]++; solve[num+1]=value[i]; //printf("1--%d\n",value[i]); dfs(need-value[i],num+1,type,i); } else { tim[i]++; solve[num+1]=value[i]; //printf("2--%d\n",value[i]); dfs(need-value[i],num+1,type+1,i); } tim[i]--; solve[num+1]=0;//回溯 } else return; } return;}int main(){ int tmp; while(1) { pv=0; memset(type,0,sizeof(type)); memset(value,0,sizeof(value)); while(1) { while(scanf("%d",&tmp)==EOF) exit(0); if(tmp==0) break; type[tmp]++; if(type[tmp]<5) value[pv++]=tmp; } sort(value,value+pv); //for(int k=0;k<pv;k++) //cout<<" "<<value[k]; while(scanf("%d",&need)!=EOF&&need) { memset(tim,0,sizeof(tim)); memset(solve,0,sizeof(solve)); memset(bestsolve,0,sizeof(bestsolve)); flag=flag_tie=false; dfs(need,0,0,0); //if(flag) printf("flag"); //if(flag_tie) printf("flag_tie"); //for(int g=0;g<6;g++) //cout<<" "<<bestsolve[g]; //printf("结束"); //system("pause"); //sort(bestsolve+1,bestsolve+4); printf("%d ",need); if(bestsolve[0]==0) { printf("---- none\n"); } else if(flag_tie) { printf("(%d): tie\n",bestsolve[5]); } else { printf("(%d):",bestsolve[5]); for(int g=1;g<=4;g++) { if(bestsolve[g]) printf(" %d",bestsolve[g]); } printf("\n"); } } } return 0;}
- poj 1010 邮票问题 DFS
- poj 1010 邮票问题
- POJ 1010 邮票
- poj 1010邮票
- 蓝桥杯 剪邮票DFS
- 邮票问题
- 邮票问题
- 邮票问题
- 邮票问题
- 邮票问题
- 邮票问题
- 邮票问题
- 邮票问题
- 邮票问题
- 邮票问题
- 邮票问题
- 迷宫问题 POJ dfs
- POJ 棋盘问题 DFS
- 八款开源 Android 游戏引擎
- Java how to program(4th)中的专业词汇ch10
- 杨毅:不够优秀就不要腆着脸继续占便宜
- java: cannot execute binary file问题的解决
- c primer plus(第五版)中文版 第五章 编程练习
- poj 1010 邮票问题 DFS
- 活着
- Static Import 用法之 Constant Utility Class
- 一致性哈希算法(Consistent Hashing)
- [转]游戏动画中欧拉角与万向锁的理解
- C++实现广义欧几里得除法计算最大公因数
- 母亲的信任
- Android学习笔记(3)————Android四大组件之三(Content Provider)(代码示例待补全)
- 26款开源网络管理工具