动态规划——最小找钱问题
生活随笔
收集整理的這篇文章主要介紹了
动态规划——最小找钱问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目:
這是一個古老而又經典的問題。用給定的幾種錢幣湊成某個錢數,一般而言有多種方式。
例如,給定了7種錢幣面值為6 2 5 10 20 50 100,用來湊299元,可以用幾種方案。我們的任務就是,給定若干個互不相同的錢幣面值,編程計算,最少需要多少個錢幣才能湊成某個給出的錢數。
思路:
1、對于這個硬幣問題,我們每次都是取硬幣,或者不取硬幣。因此我們可以將這個硬幣問題切割成若干個子問題(取不取這種硬幣),而且每次決策都會用到這個子問題。而且所有的子問題中必定存在最優解。
2、每次取硬幣,都僅僅是做出決策,判斷是否取這若干種硬幣,每次決策之后,除了n塊錢會改變之外,其他都沒有改變,都是判斷是否取這若干種硬幣的一種,因此可以說硬幣問題無后效性。
3、遞推方程
dp[i]表示金額為i時,最少錢幣組合。對每個v(j),嘗試用硬幣v(j)找錢,v(j)<=i時,dp(i)=min{dp(i),num(i-v(j))+1},找出取硬幣和不取硬幣兩種決策所得的最少硬幣數組合。
4、這個問題必須用動態規劃,不能使用貪心策略,因為貪心算法只考慮當前步,動態規劃考慮整體。
代碼:
#include <bits/stdc++.h> #define Infiniti 1000000 //定義最大值 #define MAX 20 //定義個數 using namespace std; int v[MAX];//存儲所有幣值 int dp[MAX];//存放1到n的各個值所需的幣數 int Contain(int v[],int n,int s) //n為v的len,s為金額 { int i,j,t;dp[0]=0; //初始化,幣值剛好可以付清 for(i=1;i<=s;i++) //初始化dp數組其他值為最大值 {dp[i]=Infiniti;}for(i=1;i<=s;i++) //從1到s的各個值所需的最小幣數情況 {for(j=1;j<=n;j++) //嘗試每一種幣值 {if(i>=v[j]) //幣值可以支付當前金額 dp[i]=min(dp[i],dp[i-v[j]]+1);//每種幣值可以選擇取或不取,最終求最小幣數組合情況 }}return dp[s]; //返回金額為s時最小錢幣數 } void Show(int s,int n,int t) {int i,a[MAX],j=0; //j保存幣值個數 while(s) //需支付金額不為0時 {for(i=n;i>0;i--){//可以使用該幣值且使用后余下金額仍符合最小組合 if(s-v[i]>=0&&dp[s-v[i]]==t-1){a[j++]=v[i]; //保存幣值 s-=v[i]; //總金額減少 t--; //需找出的幣數減少 break; //符合條件則跳出循環,尋找下一個s的組合 }}}for(i=0;i<j;i++)cout<<a[i]<<" "; }int main() {int n,s,t;cout<<"請輸入錢幣種數:";cin>>n;cout<<"請依次輸入各種錢幣的面值:";for (int i=1;i<=n;i++)cin>>v[i];cout<<"請輸入錢數:";cin>>s;t=Contain(v,n,s);if(t>=Infiniti) //各面值無法組合成給定s cout<<"Error!";else{cout<<"共需個數:"<<t<<endl;cout<<"各個幣值為:";Show(s,n,t);} return 0; }運行:
總結
以上是生活随笔為你收集整理的动态规划——最小找钱问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: APPIcon -(自留)
- 下一篇: 谷歌生物医学专用翻译_一个可以快速翻译浏