固定终点的最长路和最短路
来源:互联网 发布:淘宝网精品竹制鸟笼 编辑:程序博客网 时间:2024/06/09 19:42
1. 问题描述:n种硬币,面值分别是:v[1],v[2],……v[n]。给定非负整数s,可以选用多少个硬币,使得面值之和恰好为s?求出硬币数目的最大值和最小值。接下来考虑硬币问题最长路和最短路的问题相似只考虑最长路例如int dp(int s)//求最大的硬币数量{ int &ans = d[s]; if(ans>=0) return ans; for(int i = 1; i <= n; ++i) { if(s >= v[i]) { ans = max(ans, dpmax(s - v[i]) + 1); } } return ans;}针对上面计算最长路的问题 由于路径长度可以为0,S本身是0因此d=0和d的全段为0都不可以,会影响结果由于节点S不一定会走到0所以需要特殊值表示如果S走不到但是返回值却是0则可能误认为走到0所以如下修改,int dp(int s)//求最大的硬币数量{ int &ans = d[s]; if(ans!=0) return ans; ans=-(1<<30); for(int i = 1; i <= n; ++i) { if(s >= v[i]) { ans = max(ans, dpmax(s - v[i]) + 1); } } return ans;}最好的方法是加一个数组vis来表示状态i是否被访问过。
#include<iostream>#include<cstring>using namespace std;int n, s, v[100],d[100], vis[100];//vis[i]=0:标志状态i没有计算过;否则计算过int dpmax(int s);int dpmin(int s);void print(int*d,int s);//打印出组成S的硬币大小。int main(){ cin >> n >> s; for(int i = 1; i <= n; ++i) { cin >> v[i]; } memset(vis, 0, sizeof(vis)); vis[0]=1; //记忆化搜索的初始化必须将除了目标状态的所有状态设置为0 d[0]=0; cout << dpmax(s) << endl; print(d,s); cout<<endl; memset(vis, 0, sizeof(vis)); vis[0]=1; cout << dpmin(s) << endl; print(d,s); return 0;}int dpmax(int s)//求最大的硬币数量{ if(vis[s])//表示状态是否计算出 { return d[s]; } vis[s] = 1;//状态已算出标记1 int &ans = d[s];//d数组中储存的是从0到金额中每个金额所需的最大硬币数 ans = -(1<<30); for(int i = 1; i <= n; ++i)//此函数利用的是一种递归思想并且找出最小值 { if(s >= v[i]) { ans = max(ans, dpmax(s - v[i]) + 1);//先回归到最小状态,然后一个个回归在上一个状态下找出他的 //最小值返回数组d然后在回归上个状态就这样递归如果正好可以找到一个已经找到的状态直接调用d数组中得值 //另外在给的硬币数值的数组v中要遍历玩,如果找到了某个状态但还是可以找函数还是会返回直到找到最小值 //注意只有找到最后S是0是才会回归数组d才可以表示硬币为这个数目的状态 下面同理 }//本题中要求求解最大最小值两个数值用递推更加方便#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int INF=1<<30;int n,s;int v[100],minv[100],maxv[100],mincoin[100],maxcoin[100];//mincoin、maxcoin:存储对应路径上硬币的大小void print(int *d,int s);int main(){ cin>>n>>s; for(int i=0;i<n;i++) { cin>>v[i]; } minv[0]=maxv[0]=0;//递推的最下层 for(int i=1;i<=s;i++)//将最大最小值先赋值方便后面计算 { minv[i]=INF; maxv[i]=-INF; } for(int i=1;i<=s;i++)//硬币金额从1到N逐个求解 { for(int j=0;j<n;j++)//数组中存在的金额数值通过循环找出最小次数的金额 { if(i>=v[j])//硬币金额大于给的金额数值则可以继续找最小数 { if(maxv[i]<maxv[i-v[j]]+1)//maxv[i]代表的是最小数第二个循环完结后就可得出 //i-v[j]代表的是 如果金额是10 给的硬币得值是5 则10-5是一次要加1在测出maxv[5]得值然后比较大小 { maxv[i]=maxv[i-v[j]]+1; maxcoin[i]=v[j]; } if(minv[i]>minv[i-v[j]]+1) { minv[i]=minv[i-v[j]]+1; mincoin[i]=v[j]; } } } } cout<<maxv[s]<<endl; print(maxcoin,s); cout<<minv[s]<<endl; print(mincoin,s); return 0;}void print(int*d,int s){ while(s) { cout<<d[s]<<" "; s=s-d[s]; } cout<<endl;}
有关输出所有情况不解释 } return ans;}int dpmin(int s)//求最少的硬币数量{ if(vis[s])//用来标记状态是否计算出 { return d[s]; } vis[s] = 1; int &ans = d[s]; ans = 1<<30; for(int i = 1; i <= n; ++i) { if(s >= v[i]) { ans = min(ans, dpmin(s - v[i]) +1); } } return ans;}void print(int *d,int s){ for(int i=0; i<n; i++) { if(s>=v[i]&&d[s]==d[s-v[i]]+1) { cout<<v[i]<<""; print(d,s-v[i]); return; } }}
阅读全文
0 0
- 固定终点的最长路和最短路
- 硬币问题——固定终点的最长路和最短路
- 最短路--bellman-ford--以x为起点和终点的最短路
- 聪明的kk(南阳oj171)(dp固定终点的最长路)
- poj 3328(spfa)多终点多起点的最短路
- POJ 3615 floyd 求任意起点终点的最短路
- poj 3328(多起点多终点的最短路)
- 最短路最长路整理
- poj2240(Floyd最短路的变种---最长路 )Arbitrage
- 算导2(原点终点最短路)
- pku2253 记录从初始到终点最长的路径(某一部分),迪杰斯特拉求最短路
- UVa 1025 (DAG 上的动态规划,有固定终点的最短时间,逆推法)
- poj-3268 Silver Cow Party (最短路-spfa-求到同一起点,同一终点的最短路)
- ZOJ 3088 最短路 最长路
- hdu2066一个人的旅行——最短路(多起点,多终点)
- HDU 2066 一个人的旅行【最短路,多起点多终点,Dijkstra算法+spfa算法】
- HDU 2066 一个人的旅行【最短路,多起点多终点,Dijkstra算法+spfa算法】
- HDU 2923 Einbahnstrasse 最短路 多源终点
- web前端工程师还没参加工作,项目经验咋积累?用这个办法模拟项目经验非常好,找工作好找多了。
- 【javaBasic】java 8特性之运用
- 实验4 Linux系统管理
- 算法分析与设计课程作业第十二周#1#2#3#4
- 11.26日笔记
- 固定终点的最长路和最短路
- HMM经典介绍论文【Rabiner 1989】翻译(五)——HMM的三个基本问题
- 动态规划--(矩阵连乘 类似poj1651 )
- JSON字符串和对象相互转换
- samba不允许一个用户使用一个以上用户名与一个服务器或共享资源的多重连接
- mybatis框架(3)---SqlMapConfig.xml解析
- 三角形形状
- HMM经典介绍论文【Rabiner 1989】翻译(六)——概率计算问题
- logback 常用配置详解(二) <appender>