プログラミングトレーニング-両替問題(ダイナミックプランニングで)
12862 ワード
タイトル
//mを入力すると、m種類の紙幣があることを示します;//base[1]~base[m]を入力すると、各紙幣の額面が表示されます.//nを入力します.n元をこれらの額面に両替したいことを意味します.両替枚数が一番少ない場合、一番少ない枚数と額面ごとに必要な枚数を求めます.//base[1]が必ず1であると仮定すると、両替方法が見つからない場合はありません.どんな額面でも1元を何枚も両替できるからです.
サンプル入力
m=3は、3種類の紙幣があることを示し、額面はそれぞれbase[1]=1、base[2]=3、base[3]=4元で、n=100元を両替する必要がある.制限mとnは最大100を超えない.
サンプル出力
その結果、最小25枚の紙幣が必要で、それぞれ0枚1元、0枚3元、25枚4元だった.
アルゴリズム#アルゴリズム#
動的に計画する.2つのdp配列を用いる必要があり、m o n e y[i]money[i]money[i]はi元を両替するのに必要な最小限の紙幣数を表し、M i n n u m[i][j]MinNum[i][j]MinNum[i][j]MinNum[i][j]はi i i i元を両替するのに必要な額面b a s e[j]base[j]の枚数を表す.
m o n e y[0]=0 money[0]=0 money[0]=0 money[0]=0に初期化されます.なぜなら、どんな額面があっても、0 0 0 0 0元を両替するには紙幣が必要ないからです.同様にM i n N u m[0][j]=0 MinNum[0][j]=0 MinNum[0][j]=0であり、0 0 0 0元を両替するのに必要な任意の額面値は0 0 0 0枚である.
m o n e y[i]money[i]money[i]money[i]money[i]money[i]money[i]money[i]money[i]money[i−b a s e[1]+1 money[i−base[1]]+1 money[i−base[1]+1 money[i−base[2]+1 money[i−base[2]+1,…,m o n e[i−b a s e[m]+1 money[i−base[m]+1 money[i−base[m]+1 money[m]+1 money[b−base[m]+1 money[m]+1 moneyの最小値でいいです(注意判断i≧b a s e[j] f o r j = 1 ∼ m i≥base[j]\for\j=1\sim{m} i≥base[j] for j=1〜m);i≧b a s e[j]i≧base[j]i≧base[j]i≧base[j]が存在し、問題はいかなる数値も両替できると仮定しているため、j j j jが存在する.
M i n n N u m[i][j]MinNum[i][j]MinNum[i][j]MinNum[i][j]を更新するのは少し面倒ですが、上記のようにm o n e y[i]money[i]money[i−b a s e[j]+1 money[i]+1 money[j]+1(j=1~m j=1~m j=1~m)の最小値であることがわかります.このj 0 j_0 j 0に対しては、額面b a s e[j 0]base[j 0]base[j 0]+1 money[j 0]+1 money[j 0]+1 money[j 0]base[j 0]base[j 0]は必ずi i i i i i i元を両替するために選択しなければならないという意味である.したがって、M i n n N u m[i]=M i n n N u m[i−b a s e[j 0][j 0][j 0]ではない]MinNum[j 0]=MinNum[j_0]=MinNum[j_0][j_0]ではない[j_0]=MinNum[j_0]ではない]Min[j 0ではない]=MinNum[i−base[j 0]][j 0ではない],M i n n N u m[i]=M i n N u m[i−b a−b a s e[j 0][j 0]+1 MinNum[j 0]+1 MinNum[j 0]=MinNum[j_0]=MinNum[j_i−base[j_0]][j_0]+1 MinNum[i]=MinNum[i][j 0]=MinNum[i−base[ j 0]][j 0]+1.(ここでは必ずi≧b a s e[j 0]i≧base[base[j 0]i≧base[base[j 0]i≧base[j 0]i≧e[j 0])
リファレンスコード
//mを入力すると、m種類の紙幣があることを示します;//base[1]~base[m]を入力すると、各紙幣の額面が表示されます.//nを入力します.n元をこれらの額面に両替したいことを意味します.両替枚数が一番少ない場合、一番少ない枚数と額面ごとに必要な枚数を求めます.//base[1]が必ず1であると仮定すると、両替方法が見つからない場合はありません.どんな額面でも1元を何枚も両替できるからです.
サンプル入力
3
1 3 4
100
m=3は、3種類の紙幣があることを示し、額面はそれぞれbase[1]=1、base[2]=3、base[3]=4元で、n=100元を両替する必要がある.制限mとnは最大100を超えない.
サンプル出力
25
0 0 25
その結果、最小25枚の紙幣が必要で、それぞれ0枚1元、0枚3元、25枚4元だった.
アルゴリズム#アルゴリズム#
動的に計画する.2つのdp配列を用いる必要があり、m o n e y[i]money[i]money[i]はi元を両替するのに必要な最小限の紙幣数を表し、M i n n u m[i][j]MinNum[i][j]MinNum[i][j]MinNum[i][j]はi i i i元を両替するのに必要な額面b a s e[j]base[j]の枚数を表す.
m o n e y[0]=0 money[0]=0 money[0]=0 money[0]=0に初期化されます.なぜなら、どんな額面があっても、0 0 0 0 0元を両替するには紙幣が必要ないからです.同様にM i n N u m[0][j]=0 MinNum[0][j]=0 MinNum[0][j]=0であり、0 0 0 0元を両替するのに必要な任意の額面値は0 0 0 0枚である.
m o n e y[i]money[i]money[i]money[i]money[i]money[i]money[i]money[i]money[i]money[i−b a s e[1]+1 money[i−base[1]]+1 money[i−base[1]+1 money[i−base[2]+1 money[i−base[2]+1,…,m o n e[i−b a s e[m]+1 money[i−base[m]+1 money[i−base[m]+1 money[m]+1 money[b−base[m]+1 money[m]+1 moneyの最小値でいいです(注意判断i≧b a s e[j] f o r j = 1 ∼ m i≥base[j]\for\j=1\sim{m} i≥base[j] for j=1〜m);i≧b a s e[j]i≧base[j]i≧base[j]i≧base[j]が存在し、問題はいかなる数値も両替できると仮定しているため、j j j jが存在する.
M i n n N u m[i][j]MinNum[i][j]MinNum[i][j]MinNum[i][j]を更新するのは少し面倒ですが、上記のようにm o n e y[i]money[i]money[i−b a s e[j]+1 money[i]+1 money[j]+1(j=1~m j=1~m j=1~m)の最小値であることがわかります.このj 0 j_0 j 0に対しては、額面b a s e[j 0]base[j 0]base[j 0]+1 money[j 0]+1 money[j 0]+1 money[j 0]base[j 0]base[j 0]は必ずi i i i i i i元を両替するために選択しなければならないという意味である.したがって、M i n n N u m[i]=M i n n N u m[i−b a s e[j 0][j 0][j 0]ではない]MinNum[j 0]=MinNum[j_0]=MinNum[j_0][j_0]ではない[j_0]=MinNum[j_0]ではない]Min[j 0ではない]=MinNum[i−base[j 0]][j 0ではない],M i n n N u m[i]=M i n N u m[i−b a−b a s e[j 0][j 0]+1 MinNum[j 0]+1 MinNum[j 0]=MinNum[j_0]=MinNum[j_i−base[j_0]][j_0]+1 MinNum[i]=MinNum[i][j 0]=MinNum[i−base[ j 0]][j 0]+1.(ここでは必ずi≧b a s e[j 0]i≧base[base[j 0]i≧base[base[j 0]i≧base[j 0]i≧e[j 0])
リファレンスコード
#include
#define maxm 105
#define maxn 105
int main(){
int base[maxm+1], money[maxn+1], MinNum[maxn+1][maxm+1];
int n, m;
int temp = 0;
while(scanf("%d", &m)==1){
//
for(int i = 1;i <= m;i++){
scanf("%d", &base[i]);
}
scanf("%d", &n);
// dp
money[0] = 0;
for(int j = 1;j <= m;j++){
MinNum[0][j] = 0;
}
for(int i = 1;i <= n;i++){
// money[]
for(int j = 1;j <= m;j++){
if(i>=base[j]){
temp = (money[i-base[1]]<money[i-base[j]]) ? 1 : j;
}
}
money[i] = money[i-base[temp]] + 1;
// MinNum[][]
for(int j = 1;j <= m;j++){
MinNum[i][j] = MinNum[i-base[temp]][j];
}
MinNum[i][temp] = MinNum[i][temp] + 1;
}
//
printf("%d
", money[n]);
for(int j = 1;j < m;j++){
printf("%d ", MinNum[n][j]);
}
printf("%d
", MinNum[n][m]);
}
return 0;
}