连续邮资问题(回溯+动态规划)
来源:互联网 发布:数据体现不出邓肯作用 编辑:程序博客网 时间:2024/06/13 12:35
这个程序debug了好长时间....一个晚上都耗上面了
这个程序实际上每一部分并不复杂,但是动态规划那边边界错了好长时间。
题目:假设国家发行了n种不同面值的邮票,并且规定每张信封上最多只允许贴m张邮票。连续邮资问题要求对于给定的n和m的值,给出邮票面值的最佳设计,在1张信封上可贴出从邮资1开始,增量为1的最大连续邮资区间。例如,当n=5和m=4时,面值为(1,3,11,15,32)的5种邮票可以贴出邮资的最大连续邮资区间是1到70。
首先比较困难的这个题目看上去循环是没有上限的,也就是我们看似找不到循环边界,其实我们只需考虑可能生成的节点即可。
dfs(x,cur,max)其中x数组存储当前的解有哪些(如果你就是求具体数值,而不要求解的组成甚至可以省略),cur代表目前到第几种面值,当到n为止,max表示到目前为止的最大可到达邮资,而之后下一个x[cur+1]一定是取x[cur]+1~max+1,这个很好理解,max+1目前是访问不到的,那么我加入x[cur+1]后,要看看max更新到多少,而max是从max+1到
m*x[cur+1](最多就是m个最大的那个邮票,最少肯定是要更新,不然要你何用...),接下来的问题就是能否用n种邮票,面值都储存在x数组中,最多贴m张,表示出某个数,
方法是动态规划,状态转移方程dp[i,j]=min(dp[i-1][j-k*a[i]+k),其实有点像背包;(注意边界!!!!!!!)dp[i][0]=0(没有钱时0张邮票)dp[1][i]=i;(因为第一张邮票就是1,贴几块钱就是几张邮票)
话说我的程序跑的真慢,应该还能优化...
附一些数据
n= 5 m=4 {1,3,11,15,32} 最大邮资为70
n=5 m=5 {1,4,9,31,51} 最大邮资为126
n=4 m=2 {1,3,5,6}最大邮资为12
n=3 m=4 {1,5,8}最大邮资为26
n=6 m=4{1,4,9,16,38,49}最大邮资为108
n=5 m=6{1,7,12,43,52}最大邮资为216
详细的内容可以参考代码(代码打了很多注释),我前面转载的一片博客也不错,不过思路应该是差不多吧:
#include <stdio.h>#include <string.h>int n,m;//n为邮票种类,m为一封信上最多贴的邮票个数int Max;int ans[10000];//最终答案数组int min(int a,int b){ return a<b?a:b;}int panduan(int x[10000],int n,int sum)//能否用n种邮票,面值在x数组中,最多贴m张,表示出sum(是个动态规划问题,方法是求出dp[n][sum]看它是否小于sum,状态转移方程dp[i][j]=min(dp[i-1][j-k*x[i]]+k)(其中dp[i][j]表示用到第i种邮票,表示邮资为j的最少邮票 { int i,j,k; int dp[15][1005]; for (i=0;i<=n;i++) dp[i][0]=0; for (i=0;i<=sum;i++) dp[1][i]=i; for (i=2;i<=n;i++) for (j=1;j<=sum;j++) { dp[i][j]=9999; for (k=0;k<=j/x[i];k++) dp[i][j]=min(dp[i][j],dp[i-1][j-x[i]*k]+k); } if (dp[n][sum]>m) return 0; return 1; }void DFS(int x[10000],int cur,int max){ int i,j,next; if (cur==n)//如果已经得出了n种邮票 { if (max>Max)//并且它的最大值已经大于当前最大邮资数 { Max=max; for (i=1;i<=cur;i++) ans[i]=x[i];//更新答案数组 } return; } for (next=x[cur]+1;next<=max+1;next++)//如果还没得到n中邮票,那么从x[cur]+1~max+1选一个作为下一个邮资,因为max+1没法表示,所以必定到max+1为止 { x[cur+1]=next;//接下来是重点,用种类为cur+1,数目分别为x[1..cur+1]的邮票,最多使用m张,能否表示出大于max的某个数 for (i=max+1;i<=m*x[cur+1];i++)//这个数最少要为max+1(不然没有意义了),最多是x[cur+1]*m if (panduan(x,cur+1,i)==0)//如果成立 break; if (i>max+1)//如果至少让最大值更新了一次 DFS(x,cur+1,i-1); }} int main() { int i,j,max,cur; int x[1000];//中间传递的数组,存储当前的邮票值的解 scanf("%d%d",&n,&m); Max=0; max=m; cur=1; x[cur]=1; DFS(x,cur,max);//x存储当前的解,cur表示当前传递到第几种邮票,max表示目前能表示到的最大值 printf("%d\n",Max); for (i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }
- 连续邮资问题(回溯+动态规划)
- 算法:连续邮资问题(回溯+动态规划+剪枝)
- 连续邮资问题的回溯法解决办法
- 算法java实现--回溯法-连续邮资问题--子集树
- UVa 165 - Stamps(连续邮资问题)
- 连续邮资问题
- 连续邮资问题
- 连续邮资问题
- 连续邮资问题
- 连续邮资问题
- 连续邮资问题
- 连续邮资问题
- UVA165连续邮资问题
- 连续邮资问题
- 连续邮资问题
- 连续邮资问题
- 算法 连续邮资问题
- 连续邮资问题
- eclipse安卓模拟器窗口大小调整
- Android笔记(一)R文件无法生成
- 使用Zxing来实现二维码扫描
- Codeforces #341 div 2 E. Wet Shark and Blocks(矩阵快速幂)
- 编写JavaScript函数解析查询字符串
- 连续邮资问题(回溯+动态规划)
- RecyclerView 使用总结(三):点击事件、GridView等、瀑布流、动态增删
- vim使用
- 在xcode中修改整个项目名
- nodejs npm常用命令
- iOS 获取对象的全部属性、把model的所有属性和对应的值转化为字典
- python装饰器的学习笔记二
- iOS之HTTP网络编程
- Openfire集群部署不完全手册