リンクします。https://www.luogu.org/problemnew/show/P1782
個人的に、この質問は非常に良いマルチ練習の手とバックパック完全なタイトルです。
タイトル説明小Sは、すべての問題が多項式時間で解くことができると考えているので、彼は時に巡回セールスマンをバックに行く準備ができていました。出発前、彼はいくつかのアイテムを購入しました。これらの項目のn個の種類、体積Viと、WI、ディ合計メンバの値i番目があります。彼のバックパックのボリュームはCです。できるだけ多く収量を得るためにドレスアップする方法?ビッグベンは神として、彼はこの問題を解決するのは簡単でした。 しかし、彼の出発前に、彼は上の品物の数を受け取りました。李= AI * Xiの^ 2 + BI * Xiの+のCI:これらの商品Mの項目がある、分布Yi及びXIの容積の値との関係は、i番目の要素です。これは良いことですが、小さなSが対処する方法がわからないので、彼は超神ベンを(それはあなたです)が見つかり、彼はこの問題を解決する助けてください。 入出力フォーマット入力フォーマット:
3つの数字の最初の行のN、M、C、タイトルに記載されているように。 次のn行、タイトル内の3数Viと、WI、ジを有する各行。 タイトルに記載されているようにm行は、3つの数字を有する各列は、BI、CIを愛。 出力フォーマット:
最大値の場合のみ1行、。 |
バックパックの話をするので、我々は再びいくつかの基本的なバックパックのレビューに来ます:
1.01バックパック:
言うまでもなく、01バックパックは、あなたが選択したかを選択、あなたがから転送選択する前にその状態で状態を選択し、アイテムのためです。
擬似コード:
以下のため:(I)1 - > N のための:(J)maxv-> V [I] F [J] = MAX(F [JV [I] + W [i])と
2.完全にバックパック:
十分考慮にバックパックを取ると、各アイテムの数に制限を保持するが、本質的には、01とバックパックとの間の差からだけでなく、状態遷移点であることができ、これはと等価である(選挙前の状態からの転送は、また、選挙後の状態であってもよいです反復選択)への書き込みサイクルである第2層:
以下のため:(I)1 - > N のための:(J)は、V [I] - > MAXV F [J] = MAX(F [JV [I] + W [i])と
3.複数のバックパック:
項目は、列挙の数を元に基づいて増加したが、サイクルから他のことができないので、複数のバックパックは、アイテムの数を制限します。
以下のため:(I)1 - > N のための:(J)maxv-> V [i]の ための:(K)1 - > C [I](k個*のV [I] <= J) [J] F =最大([JK * V [I] + Kの* F [i]がW)
バックパックの残りの部分は後で言いました。実際には、書くのが面倒です
だから、それのアイデアがあります!
この質問は少し欺瞞的データであるが、我々は土台の上にいくつかの最適化を行う必要があります。
- 単調なキュー:
単調を最適化するためにキューを考えてみましょう:
私たちは、最も価値を維持、キューが単調最適化するために使用することができます。
- 読み込みの最適化(ナンセンス)
#include<iostream> #include<cstdio> using namespace std; const int N=10010; int n,m,cool; int v[N],w[N],d[N]; int a[10],b[10],c[10]; int tietie[N]; int fu[N],sai[N]; int main(){ scanf("%d%d%d",&n,&m,&cool); for(int i=1;i<=n;i++){ scanf("%d%d%d",&v[i],&w[i],&d[i]); } for(int i=1;i<=m;i++){ scanf("%d%d%d",&a[i],&b[i],&c[i]); } for(int i=1;i<=n;i++){ for(int j=0;j<v[i];j++){ for(int k=0,bu=0,ki=0;k*v[i]+j<=cool;k++){ int matsuri=tietie[j+k*v[i]]-k*w[i]; while(bu!=ki&&matsuri>fu[ki-1]) ki--; sai[ki]=k,fu[ki++]=matsuri; if(sai[bu]+d[i]<k) bu++; fu[k*v[i]+j]=fu[bu]+k*w[i]; } } } for(int i=1;i<=m;i++){ for(int j=cool;j>=0;j--){ for(int k=0;k<=j;k++){ if(tietie[j]<tietie[j-k]+(k*a[i]+b[i])*k+c[i]) tietie[j]=tietie[j-k]+(k*a[i]+b[i])*k+c[i]; } } } printf("%d",tietie[cool]); return 0; }
奇怪的是没有过,所以暂时放这了,以后再改。