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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

(DAG+固定终点的最长路和最短路)硬币问题

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

##題目:
有n種硬幣,面值分別為v1, v2, …, vn,每種都有無限多。給定非負整數S,可以選用多少個硬幣,使得面值之和恰好為S?輸出硬幣數目的最小值和最大值。

Input
第一行兩個整數,n,S(1≤n≤100, 0≤S≤100000)。
第二行n個整數vi-1…n(1≤vi≤S)。

Output
第一行兩個整數,分別表示硬幣數目的最小值 a 和最大值 b 。無解則輸出 -1 。
第二行 a 個整數分別表示使用的是第幾種硬幣。
第三行 b 個整數分別表示使用的是第幾種硬幣。

Sample Input
6 12
1 2 3 4 5 6

Sample Output
2 12
6 6
1 1 1 1 1 1 1 1 1 1 1 1

##分析與解

假如s是12,怎么弄個金錢加加減減就到十二呢
假設每個結點表示剩的錢數
怎么和DAG想到一塊,可以這么想,現在已知一個路的起點s和終點0,每多加一個錢,s就變到另一個數s2,現在找s2和終點0的路,這樣就成了一個DAG

##思考
我們用遞推,想找剩下s元到剩下零元的最小使用錢的次數
現在找最短路徑的話
遞推公式:dmin[i]=min(dmin[i],dmin[i-v[j]]+1)
我們初始化dmin[0]=0剩下零元到零元不需要錢,次數為零
dmin[i]的話就是看dmin[i]到零元的最小使用錢次數,他需要和dmin[i-v[j]]+1比較,其中+1是說dmin[i-v[j]]加上v[j],使用了dmin[i-v[j]]加上一次使用v[j]的次數
我們可以發現dmin[s]可以由dmin[0]向上推出

那不妨把遞推公式轉換成迭代

如果剩下的錢i減去v[j]大于零,說明可以通過dmin[i-v[j]]+1來確定dmin[i]
那么假設我們的dmin[i]就等于dmin[i-v[j]]+1,并且dmin[0]等于0,所以這樣一步一步推出dmin[s]

由于題目說字典序,我們再寫最大最小值時候也是遇見大于max的就存標號,更改max,后面來個等于max的,我們不能再存標號,因為我們要的是第一個數,所以后面來的必須要大于max,我們才改標號

這個也是一樣的道理,必須有新的dmin[i-v[j]]+1比之前的dmin[i-v[j2]]+1小的時候我們替換掉dmin[i]的值。
由于要考慮輸出,輸出的都是v[j],那我們就要記錄每一個i他減的v[j]是什么,就是當dmin[i]>dmin[i-v[j]]+1時,我們不僅替換dmin[i]=dmin[i-v[j]]+1,還要替換path_min[i]=j,path_min[i-v[j]]=j2,如果i-v[j]=0,此時說明v[j]+v[j2]=s

我這輸出沒排序,如果要排序的話,存到數組里,然后輸出

int V[maxN];i是第幾種,v[i]是第i種的價值
int Dmin[maxS];dmin[i]是i到0所需的最小路徑
int Dmax[maxS];
int path_min[maxS];path_min[i]是最小路徑中由i走到下一個結點所減去的那個數v[j]的下標j
int path_max[maxS];

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std;const int maxN=200; const int maxS=200000; const int inf=2000000000; int n,S; int V[maxN]; int Dmin[maxS]; int Dmax[maxS]; int path_min[maxS]; int path_max[maxS];void print_ans(int *d,int s){while(s){printf("%d ",d[s]);s-=V[d[s]];} }int main() {cin>>n>>S;for (int i=1;i<=n;i++){cin>>V[i];}for (int i=1;i<=S;i++){Dmin[i]=inf;Dmax[i]=-inf;}Dmin[0]=0;Dmax[0]=0;for (int i=1;i<=S;i++){for (int j=1;j<=n;j++)if (i>=V[j]){if (Dmin[i]>Dmin[i-V[j]]+1)//+1走的v【j】 {Dmin[i]=Dmin[i-V[j]]+1;path_min[i]=j;}if (Dmax[i]<Dmax[i-V[j]]+1){Dmax[i]=Dmax[i-V[j]]+1;path_max[i]=j;}}}cout<<Dmin[S]<<' '<<Dmax[S]<<endl;print_ans(path_min,S);printf("\n");print_ans(path_max,S);printf("\n");return 0; }

總結

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

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