トップページに戻る
次のPHPのサンプルへ
前のPHPのサンプルへ
Q14 現地で使いやすい両替
PHPのソース
<?php
Solve(11254);
Solve(45678);
class ResultClass
{
public $ToatlCoinCnt;
public $EachCoinCntArr;
}
function Solve($pYen)
{
$CoinCombiArr = DeriveCoinCombiArr();
$ResultArr = array();
foreach ($CoinCombiArr as $EachCoinCombi){
$RestYen = $pYen - array_sum($EachCoinCombi);
if ($RestYen < 0) continue;
$CurrResult = new ResultClass();
$CurrResult->ToatlCoinCnt = count($EachCoinCombi);
$CurrResult->EachCoinCntArr = array();
foreach($EachCoinCombi as $EachCoinVal){
$CurrResult->EachCoinCntArr[$EachCoinVal] = 1;
if($EachCoinVal <= $RestYen){
$ModVal = $RestYen % $EachCoinVal;
$SyouVal = ($RestYen - $ModVal) / $EachCoinVal;
$CurrResult->EachCoinCntArr[$EachCoinVal] += $SyouVal;
$CurrResult->ToatlCoinCnt += $SyouVal;
$RestYen = $ModVal;
}
}
if($RestYen == 0) $ResultArr[] = $CurrResult;
}
//使用した紙幣と硬貨の種類の最大値を求める
$MaxCoinCount = 0;
foreach($ResultArr as $EachResult){
$CurrCnt = count($EachResult->EachCoinCntArr);
if($MaxCoinCount < $CurrCnt)
$MaxCoinCount = $CurrCnt;
}
//使用した紙幣と硬貨の種類が最大値での、
//全体の枚数の最小値を求める
$MinToatlCoinCnt = PHP_INT_MAX;
foreach($ResultArr as $EachResult){
if(count($EachResult->EachCoinCntArr) < $MaxCoinCount)
continue;
if($EachResult->ToatlCoinCnt < $MinToatlCoinCnt)
$MinToatlCoinCnt = $EachResult->ToatlCoinCnt;
}
foreach($ResultArr as $EachResult){
if(count($EachResult->EachCoinCntArr) < $MaxCoinCount)
continue;
if($EachResult->ToatlCoinCnt < $MinToatlCoinCnt)
continue;
printf('金額が%d円での、最小枚数は%d枚で、内訳は' , $pYen , $MinToatlCoinCnt);
var_export($EachResult->EachCoinCntArr);
echo PHP_EOL;
}
}
class JyoutaiDef
{
public $CurrInd;
public $CurrArr;
}
//紙幣と硬貨の組合せの配列を返す
function DeriveCoinCombiArr()
{
$CoinArr = array(1,5,10,50,100,500,1000,2000,5000,10000);
$UB = count($CoinArr)-1;
$WillReturn = array();
$Stk = new SplStack();
$WillPush = new JyoutaiDef();
$WillPush->CurrInd = 0;
$WillPush->CurrArr = array();
$Stk->push($WillPush);
while($Stk->isEmpty() == false){
$Popped = $Stk->pop();
for($I = $Popped->CurrInd ; $I <= $UB ; $I++){
$WillPush = clone $Popped;
$WillPush->CurrInd = $I+1;
$WillPush->CurrArr[] = $CoinArr[$I];
$Stk->push($WillPush);
$WillAdd = $WillPush->CurrArr;
rsort($WillAdd);
$WillReturn[] = $WillAdd;
}
}
return $WillReturn;
}
実行結果
金額が11254円での、最小枚数は19枚で、内訳はarray (
5000 => 1,
2000 => 2,
1000 => 1,
500 => 2,
100 => 1,
50 => 2,
10 => 4,
5 => 2,
1 => 4,
)
金額が45678円での、最小枚数は17枚で、内訳はarray (
10000 => 3,
5000 => 2,
2000 => 2,
1000 => 1,
500 => 1,
100 => 1,
50 => 1,
10 => 2,
5 => 1,
1 => 3,
)
解説
深さ優先探索で、組合せを列挙し、
貪欲法を使ってます。