A銀行は現金の引き出しのためにマシンをインストールすることを計画しています。マシンは、要求された現金の金額のために適切な@法案を提供することができます。正確N機械用途の異なる紙幣金種は、Dkは、K = 1、N、および各金種Dkのための機械は、NK紙幣の供給を持っていると言います。例えば、
N = 3、N 1 = 10、D1 = 100、N2 = 4、D2 = 50、N3 = 5、= 10のD3
手段は、マシンは、@ 100それぞれの10枚の紙幣、@ 50それぞれの4枚の紙幣の供給を有します、及び10それぞれ@ 5つの手形。
マシンはより少ない現金の最大量を計算したり効果的にマシンの利用可能貨幣供給に応じて配信することができ、現金と同等のプログラムを提供し、書くべき現金の呼び出し現金、要求量。
ノート:
@マシンが提供する通貨のシンボルです。例えば、@は、ドル、ユーロ、ポンドなどのために立つこと入力
プログラムの入力は、標準入力からです。入力内の各データセットは、特定のトランザクションを表し、フォーマットを有する:
現金N N1、N2 D1 D2 ... nNのDN
0 <=現金の量は、0 <= N <= 10を現金<= 100000要求され紙幣の金種の数及び0 <= NK <= 1000 Dkの額面のために利用可能な紙幣の数であり、1 <= Dkを<= 1000、K = 1、N。ホワイトスペースは、入力中の数字の間を自由に発生する可能性があります。入力データが正しいです。出力
以下の例に示すように、データの各セットのためのプログラムは、別の行に、標準出力に結果を出力します。
サンプル入力
735 3 4 125 6 5 3 350 633 4 500 30 6 100 1 5 0 1 735 0 0 3 10 100 10 50 10 10サンプル出力
735 630 0 0ヒント
第一のデータセットは、現金の量は735 @で要求されたトランザクションを指定します。125 @ 4枚の紙幣、5 @ 6枚の紙幣、350 @の3枚の紙幣:マシンが3つの紙幣の金種を含有します。マシンは、要求された現金の正確な量を提供することができます。
後者の場合には、マシンの貨幣供給は、要求された現金の正確な量に適合していません。配信可能な最大キャッシュ・フローは630 @です。配信現金を照合するための機械で法案を結合するいくつかの可能性があり得ることに注意してください。
三番目のケースでは、マシンは空であり、現金は配信されません。第4のケースでは要求された現金の額は、そのため、機械には、CAを提供しない、0 @で、
トピック分析(ナップザック問題変形):
複数のバックパック、あなたにいくつかのお金を与える、それぞれがお金の最大量が現金を超えていない見つけるためにあなたを必要とし、NK張銭を持っています。
あなたはn個の項目があり、バックパック(現金容量)に相当し、各項目には、NIがあります。バックパックの最大値を求めます。
Aは考えました:
我々は、各項目をk =ログ(NI)は、各項目の重みが1,2,4であるKと分割することができる、...、2 ^ K、NI-(2 ^(K + 1)-1 )、その後、これらの項目に0-1ナップザックを行います。
前記F意味として[J]:1の場合、それは、iフロント物品(通貨)が最大値Jとして実装することができることを示し、0であり、それは取らないように示しています。
F [J] = F [J] || F [JK * [I] W]。
コード:
#include <queue> #include <vector> #include <cstdio> #include <utility> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int cash,n,ans,w[1005],d[1005]; bool f[100005]; int main() { cin.sync_with_stdio(false); while(cin>>cash>>n) { memset(f,0,sizeof(f)); f[0] = true; for(int i = 1; i <= n; i++){ cin>>d[i]>>w[i]; int k = 1; for(; d[i]-2*k+1 > 0; k*=2) { for(int j = cash; j >= k*w[i]; j--) f[j] = f[j] || f[j-k*w[i]];//检测是否可以填满容量为j的背包 }//log(d[i])种背包 k = d[i]-k+1;//第i种物品的最后一种 for(int j = cash; j >= k*w[i]; j--) f[j] = f[j] || f[j-k*w[i]]; } int j = cash; for(; j; j--) if(f[j]) break;//第一个不为0的即是最大值 cout<<j<<endl; } }
思考2:
ケースF [I]でFの意味を変更する方法で、[I] [J]、「コンテストのプログラミングの課題は、」[J] iは財のいくつかの種類に残っていたとき、私はJを取得する前に、そこにアップ表します
IF(F [j]> = 0)F [J] = D [i]は、
他(J> = W [i])とする場合、F [J] = F [JW [I]] - 1。
注約肯定的であるが、値は届くの代わりに負、負の言葉かもしれないが、それは問題ではないfは、我々が懸念している、これは影響を与えません。
#include <queue> #include <vector> #include <cstdio> #include <utility> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int cash,n,ans,w[1005],d[1005],f[100005]; int main() { cin.sync_with_stdio(false); while(cin>>cash>>n) { memset(f,-1,sizeof(f)); for(int i = 1;i <= n;i++) cin>>d[i]>>w[i]; for(int i = 1;i <= n;i++) { f[0] = d[i]; for(int j = 1;j <= cash;j++) { if(f[j] >= 0) f[j] = d[i]; else if(j >= w[i]) f[j] = f[j-w[i]] - 1; } } ans = 0; for(int j = cash;j;j--) if(f[j] >= 0) { ans = j; break; } cout<<ans<<endl; } }
参考文献:
1、https://blog.csdn.net/u014258433/article/details/51614734
2、「プログラミングの挑戦」