日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

硬币问题——固定终点的最长路和最短路

發布時間:2023/12/1 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 硬币问题——固定终点的最长路和最短路 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
問題描述:

?? ??? 有n種硬幣,面值分別為V1,V2...,Vn,每種都有無限多。給定非負整數S,可以選用多少個硬幣,使得面值之和恰好為S?輸出硬幣數目的最小值和最大值。0 <= n <= 100, 0 <= S <= 10000, 1 <= Vi <= S。


分析:
?? ??? 本題的本質還是DAG上的路徑問題。我們把每種面值看作一個點,表示"還需要湊足的面值",則初始狀態為S,目標狀態為0。若當前的狀態i,每使用一個硬幣j,狀態便轉移到i-Vj。這個模型和嵌套矩形一題類似,但也有些明顯的不同之處:嵌套矩形中并沒有確定路徑的起點和終點(可以把任意矩形放在第一個和最后一個),而本題的起點必須是S,終點必須是0。把終點固定之后"最短路"才是有意義的。在嵌套矩形中,最短序列顯然是空(如果不允許空的話,就是單個矩形,不管怎樣都是平凡的),而本題的最短路徑卻不是那么容易確定的。


?????? 接下來考慮"硬幣問題"。注意到最長路和最短路的求法是類似的,下面只考慮最長路。由于終點固定,d(i)的確切含義變為"從節點i出發到節點0的最長路徑長度"。

下面是求最長路的代碼(錯誤的):

int dp(int S)//錯誤 {int& ans=d[S];if(ans>=0) return ans;ans=0;for(int i=1;i<=n;i++)if(S>=V[i])ans=max(ans,dp(S-V[i])+1);return ans; } /*此代碼有一個致命的錯誤,即由于節點S不一定真的能到達節點0,所以需要用特殊的d[S]值表 示"無法到達",但在上述代碼中,如果S根本無法繼續往前走,返回值是0,將被誤以為是"不能 走已經到達終點"的意思。*/



正確的解法一:

int dp(int S) {int& ans=d[S];if(ans != -1) return ans;ans=-1<<30;for(int i=1;i<=n;i++)if(S>=V[i])ans=max(ans,dp(s-V[i])+1);return ans; } 注意:在記憶化搜索中,如果用特殊值表示"還沒有算過",則必須將其和其他特殊值(如無解)區分開。


正確的解法二:

int dp(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=max(ans,dp(S-V[i])+1);} return ans; } ?????? 盡管多了一個數組,但可讀性增強了許多:再也不用擔心特殊值之間的沖突了,在任何情況下,記憶化搜索的初始化都可以用memset(vis,0,sizeof(vis))執行。



????? 本題要求最小、最大兩個值,記憶化搜索就必須寫兩個。在這種情況下,還是遞推來得更加方便(此時需注意遞推的順序):

min[0]=max[0]=0; for(int i=1;i<=n;i++) {min[i]=INF; max[i]=-INF; } for(int i=1;i<n;i++)for(int j=1;j<=v;j++)if(i>=V[j]){min[i]=min(min[i],min[i-V[j]]+1);max[i]=max(max[i],max[i-V[j]]+1);} printf("%d %d\n",min[S],max[S]);


完整代碼:

#include "stdio.h" #define INF 1<<30 #define maxn 100+10 int V[maxn],n; int min[maxn],max[maxn];inline int Min(int a,int b){return a<b?a:b;} inline int Max(int a,int b){return a>b?a:b;}//打印可行的方案 void print_ans(int* d,int S){for(int i=1;i<=n;i++){if(S>=V[i] && d[S]==d[S-V[i]]+1){printf("%d ",V[i]);print_ans(d,S-V[i]);break;}} }int main() {int S;//輸入面值S和面值的種數n while(~scanf("%d%d",&S,&n)){ for(int i=1;i<=n;i++){scanf("%d",&V[i]);}max[0]=0; min[0]=0;for(int i=1;i<=S;i++){min[i]=INF; max[i]=-INF;}//遞推實現 for(int i=1;i<=S;i++){for(int j=1;j<=n;j++){if(i>=V[j]){min[i]=Min(min[i],min[i-V[j]]+1);max[i]=Max(max[i],max[i-V[j]]+1);}}}print_ans(min,S); printf(" min\n");print_ans(max,S); printf(" max\n");printf("min:%d max:%d\n",min[S],max[S]); }return 0; }

總結

以上是生活随笔為你收集整理的硬币问题——固定终点的最长路和最短路的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。