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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

信息学奥赛一本通 1844:【06NOIP提高组】金明的预算方案 | 洛谷 P1064 [NOIP2006 提高组] 金明的预算方案

發(fā)布時間:2025/3/17 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 信息学奥赛一本通 1844:【06NOIP提高组】金明的预算方案 | 洛谷 P1064 [NOIP2006 提高组] 金明的预算方案 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

【題目鏈接】

ybt 1844:【06NOIP提高組】金明的預(yù)算方案
洛谷 P1064 [NOIP2006 提高組] 金明的預(yù)算方案

【題目考點】

1. 動態(tài)規(guī)劃:分組背包

2. 動態(tài)規(guī)劃:依賴背包

【解題思路】

解法1:分組背包

已知第i個商品的價格v[i],重要程度w[i],求出第i個商品的價值c[i] = v[i]*w[i]

  • 狀態(tài)定義:dp[i][j]為使用j元錢買前i個主件及其附件能得到的最大價值
  • 狀態(tài)轉(zhuǎn)移方程:思考已有j元錢,如何購買第i個主件及其附件
  • 如果不買第i個主件及其附件,dp[i][j]為使用j元錢買前i-1個主件及其附件能得到的最大價值,即dp[i][j] = dp[i-1][j]

  • 如果買第i個主件及其附件,這里要把第i個主件及其選擇的附件整合成一個商品。該商品的價格是選擇的主、附件商品的價格的和,價值是選擇的主、附件商品價值的和。這些整合的商品相當(dāng)于一個商品組,在這一組中只能選擇其中一種商品。這就是分組背包的模型。

    1)如果只選主件,那么該商品價格為v[i],價值為c[i]。
    2)如果該主件存在1個附件i1,選擇主件及第1個附件,整合后的商品價格為 v[i]+v[i1],價值為c[i]+c[i1]。
    3)如果該主件存在2個附件i1與i2,選擇主件與第2個附件,整合后商品的價格為v[i]+v[i2],價值為c[i]+c[i2]。
    4)如果該主件存在2個附件i1與i2,選擇主件與第1,2個附件,整合后商品的價格為v[i]+v[i1]+v[i2],價值為c[i]+c[i1]+c[i2]。

    記整合后的商品價格為vx,價值為cx,那么如果買這個整合后的商品
    dp[i][j]為使用j-vx元錢買前i-1個主件及其附件能得到的最大價值加上cx,即dp[i][j] = dp[i-1][j-vx]+cx。
    把買每種可能的整合商品時的dp[i][j]都求出來。

  • 將在第1點和第2點中求出的所有dp[i][j]求最大值,作為dp[i][j]的值。

  • 解法2:依賴背包

    該問題的配件數(shù)最多2個,配件的組合情況比較容易得到。如果有x個配件,那配件的組合情況將為x個元素構(gòu)成的集合的子集個數(shù),為2x2^x2x個。當(dāng)x較大時,就無法計算了。
    依賴背包的思路為:針對每個主件該如何選附件,做一次小的01背包問題,求在不同金錢限制下,在對附件做不同選擇時得到最大價值。
    已知第i個商品的價格v[i],重要程度w[i],求出第i個商品的價值c[i] = v[i]*w[i]

  • 狀態(tài)定義:dp[i][j]為使用j元錢買前i個主件及其附件能得到的最大價值
  • 狀態(tài)轉(zhuǎn)移:
    外層循環(huán)i從1到m,每次循環(huán)求出在擁有任意錢數(shù)(錢數(shù)范圍0~n)下,買前i個主件及其附件能得到的最大價值
    (1) 不買第i主件,那么無論j為任意值,dp[i][j] = dp[i-1][j]
    (2)j為任意值,確定要買第i主件,那么一定有j >= v[i],
    設(shè)狀態(tài)dp1[k][j]表示j元錢買前i-1個主附件、第i個主件以及第i主件的前k個配件可以得到的最大價值。
    (3)dp1的初始狀態(tài):dp1[0][j]為只買第i主件不買配件的情況,即為用j-v[i]的錢買前i-1個主件得到的最大價值加上第i主件的價值c[i]。即dp1[0][j] = dp[i][j-v[i]]+c[i]
    (4)此時針對dp1狀態(tài)做01背包問題,外層循環(huán)遍歷i的各個附件,內(nèi)層為可以使用的錢數(shù),主要這個錢數(shù)包括了主件的花銷。
    記第k附件價格為vx,價值為cx。
    如果剩余的錢買了該附件后,剩下的錢還足夠買主件,即j-vx >= v[i],那么買該附件的價值為用j-vx的錢買前k-1個附件(包括第i主件與前i-1個主件的東西)的最大價值加上第k附件的價值。不買該附件,那就是用j的錢買前k-1個附件(包括第i主件與前i-1個主件的東西)能得到的最大價值。二者取最大值。為:dp1[k][j] = max(dp1[k-1][j], dp1[k-1][j-vx]+cx);
    如果買了該附件后,剩下的錢無法再買主件,那么不買該附件。
    (5)pnum為主件i的附件個數(shù)。dp1[pnum][j]即為用j元錢購買前i-1個主附件、第i主件以及i的前pnum個附件能獲得的最大價值。而dp[i][j]的概念為用j元錢購買前i個物品的主附件能獲得的最大價值,二者的概念是等同的。所以這里用dp1[pnum][j]的值更新dp[i][j]的值,取最大值。
  • 【題解代碼】

    解法1:分組背包

    • 二維狀態(tài)
    #include<bits/stdc++.h> using namespace std; #define M 65 #define N 40000 struct Item {int v, c;//v:價格 c:價值:為價格*重要程度Item(){}Item(int a, int b):v(a),c(b){} }; Item a[M];//a[i]:第i個物品 vector<Item> g[M];//g[i]為第i個商品分組,即保存主件i的所有可能整合商品(包括有無附件), vector<int> f[M];//f[i]中保存主件i的附件的編號, int dp[M][N];//dp[i][j]:使用j元錢買前i個主件及其可能的附件能得到的最大價值 int main() {int n, m, v, p, q, zn;cin >> n >> m;for(int i = 1; i <= m; ++i){cin >> v >> p >> q;//v價格,p重要程度,q對應(yīng)主件 a[i].v = v;//第i商品價格 a[i].c = v*p;//第i商品價值 if(q == 0)//如果q是主件g[i].push_back(a[i]);//分組i添加商品 else//如果q是附件 f[q].push_back(i);//主件q的配件列表增加i }for(int i = 1; i <= m; ++i)//構(gòu)造商品分組{if(g[i].size() > 0)//如果分組i中有商品,說明i是主件{ int i1, i2;//現(xiàn)在要看主件i商品 i1,i2:附件 if(f[i].size() == 1)//如果只有1個附件 {i1 = f[i][0];g[i].push_back(Item(a[i].v+a[i1].v, a[i].c+a[i1].c));//整合主件與附件1 }else if(f[i].size() == 2){i1 = f[i][0], i2 = f[i][1];g[i].push_back(Item(a[i].v+a[i1].v, a[i].c+a[i1].c));//主件與附件1 g[i].push_back(Item(a[i].v+a[i2].v, a[i].c+a[i2].c));//主件與附件2 g[i].push_back(Item(a[i].v+a[i1].v+a[i2].v, a[i].c+a[i1].c+a[i2].c));//主件與附件1,2 }}}for(int i = 1; i <= m; ++i)//選擇主件m {for(int j = 0; j <= n; ++j)//最大錢數(shù){dp[i][j] = dp[i-1][j];//不買主件i及其附件。如果遇到附件,也要運行這一句。 for(int k = 0; k < g[i].size(); ++k)//選擇分組i中的一個商品。如果是附件,g[i].size()為0,該循環(huán)不會運行 {int vx = g[i][k].v, cx = g[i][k].c;if(j >= vx) dp[i][j] = max(dp[i][j], dp[i-1][j-vx]+cx);} }}cout << dp[m][n];return 0; }
    • 滾動數(shù)組優(yōu)化,變?yōu)橐痪S狀態(tài)
    #include<bits/stdc++.h> using namespace std; #define M 65 #define N 40000 struct Item {int v, c;//v:價格 c:價值:為價格*重要程度Item(){}Item(int a, int b):v(a),c(b){} }; Item a[M];//a[i]:第i個物品 vector<Item> g[M];//g[i]為第i個商品分組,即保存主件i的所有可能整合商品(包括有無附件), vector<int> f[M];//f[i]中保存主件i的附件的編號, int dp[N];//滾動數(shù)組優(yōu)化為1維數(shù)組 原狀態(tài):dp[i][j]:使用j元錢買前i個主件及其可能的附件能得到的最大價值 int main() {int n, m, v, p, q, zn;cin >> n >> m;for(int i = 1; i <= m; ++i){cin >> v >> p >> q;//v價格,p重要程度,q對應(yīng)主件 a[i].v = v;//第i商品價格 a[i].c = v*p;//第i商品價值 if(q == 0)//如果q是主件g[i].push_back(a[i]);//分組i添加商品 else//如果q是附件 f[q].push_back(i);//主件q的配件列表增加i }for(int i = 1; i <= m; ++i){if(g[i].size() > 0)//如果分組i中有商品,說明i是主件{ int i1, i2;//現(xiàn)在要看主件i商品 i1,i2:附件 if(f[i].size() == 1)//如果只有1個附件 {i1 = f[i][0];g[i].push_back(Item(a[i].v+a[i1].v, a[i].c+a[i1].c));//整合主件與附件1 }else if(f[i].size() == 2){i1 = f[i][0], i2 = f[i][1];g[i].push_back(Item(a[i].v+a[i1].v, a[i].c+a[i1].c));//主件與附件1 g[i].push_back(Item(a[i].v+a[i2].v, a[i].c+a[i2].c));//主件與附件2 g[i].push_back(Item(a[i].v+a[i1].v+a[i2].v, a[i].c+a[i1].c+a[i2].c));//主件與附件1,2 }}}for(int i = 1; i <= m; ++i)//選擇主件m {if(g[i].size() == 0)continue;for(int j = n; j >= 0; --j)//最大錢數(shù){for(int k = 0; k < g[i].size(); ++k)//選擇分組i中的一個商品。如果是附件,g[i].size()為0,該循環(huán)不會運行 {int vx = g[i][k].v, cx = g[i][k].c;if(j >= vx) dp[j] = max(dp[j], dp[j-vx]+cx);} }}cout << dp[n];return 0; }

    解法2:依賴背包

    • 二維狀態(tài)
    #include<bits/stdc++.h> using namespace std; #define M 65 #define N 40000 struct Item {int v, c;//v:價格 c:價值:為價格*重要程度Item(){}Item(int a, int b):v(a),c(b){} }; Item a[M];//a[i]:第i個物品 vector<int> f[M];//f[i]中保存主件i的附件的編號, int dp[M][N];//dp[i][j]:使用j元錢買前i個主件及其可能的附件能得到的最大價值 int dp1[5][N];//dp1[i][j]:在關(guān)注某主件i的情況下,j元錢購買i的前k個附件可以得到的最大價值 bool isMain[M];//isMain[i]:i是不是主件 int main() {int n, m, v, p, q;cin >> n >> m;for(int i = 1; i <= m; ++i){cin >> v >> p >> q;//v價格,p重要程度,q對應(yīng)主件 a[i].v = v;//第i商品價格 a[i].c = v*p;//第i商品價值 if(q > 0)f[q].push_back(i);//主件q的配件列表增加i elseisMain[i] = true;}for(int i = 1; i <= m; ++i)//選擇主件m {int pnum = f[i].size();//配件數(shù)量 for(int j = 0; j <= n; ++j)//最大錢數(shù)dp[i][j] = dp[i-1][j];//不買主件i及其附件。如果遇到附件,也要運行這一句。if(isMain[i] == false)//i是附件continue; memset(dp1, 0, sizeof(dp1));//dp1[k][j]:j元錢購買1~i-1的主副件及第i主件及i的前k個附件可以得到的最大價值for(int j = a[i].v; j <= n; ++j)//初始情況:不添加附件 只添加主件 dp1[0][j] = dp[i-1][j-a[i].v] + a[i].c;for(int k = 1; k <= pnum; ++k)//選擇i的第k個附件{ int vx = a[f[i][k-1]].v, cx = a[f[i][k-1]].c;//配件k的價格和價值。vector下標(biāo)從0開始,所以用的時候?qū)慿-1。 for(int j = a[i].v; j <= n; ++j){if(j-a[i].v >= vx)//買主件后剩下的錢還可以買第k附件 dp1[k][j] = max(dp1[k-1][j], dp1[k-1][j-vx]+cx);elsedp1[k][j] = dp1[k-1][j];}}for(int j = a[i].v; j <= n; ++j)dp[i][j] = max(dp[i][j], dp1[pnum][j]);}cout << dp[m][n];return 0; }
    • 滾動數(shù)組優(yōu)化 一維狀態(tài)
    #include<bits/stdc++.h> using namespace std; #define M 65 #define N 40000 struct Item {int v, c;//v:價格 c:價值:為價格*重要程度Item(){}Item(int a, int b):v(a),c(b){} }; Item a[M];//a[i]:第i個物品 vector<int> f[M];//f[i]中保存主件i的附件的編號, int dp[N];//滾動數(shù)組優(yōu)化 dp[i][j]:使用j元錢買前i個主件及其可能的附件能得到的最大價值 int dp1[N];//滾動數(shù)組優(yōu)化 dp1[i][j]:在關(guān)注某主件i的情況下,j元錢購買i的前k個附件可以得到的最大價值 bool isMain[M];//isMain[i]:i是不是主件 int main() {int n, m, v, p, q;cin >> n >> m;for(int i = 1; i <= m; ++i){cin >> v >> p >> q;//v價格,p重要程度,q對應(yīng)主件 a[i].v = v;//第i商品價格 a[i].c = v*p;//第i商品價值 if(q > 0)f[q].push_back(i);//主件q的配件列表增加i elseisMain[i] = true;}for(int i = 1; i <= m; ++i)//選擇主件m {int pnum = f[i].size();//配件數(shù)量 if(isMain[i] == false)//i是附件continue; memset(dp1, 0, sizeof(dp1));//dp1[k][j]:j元錢購買1~i-1的主副件及第i主件及i的前k個附件可以得到的最大價值for(int j = a[i].v; j <= n; ++j)//初始情況:不添加附件 只添加主件 dp1[j] = dp[j-a[i].v] + a[i].c;for(int k = 1; k <= pnum; ++k)//選擇i的第k個附件{ int vx = a[f[i][k-1]].v, cx = a[f[i][k-1]].c;//配件k的價格和價值。vector下標(biāo)從0開始,所以用的時候?qū)慿-1。 for(int j = n; j >= a[i].v+vx; --j)dp1[j] = max(dp1[j], dp1[j-vx]+cx);//買主件后剩下的錢還可以買第k附件 }for(int j = a[i].v; j <= n; ++j)dp[j] = max(dp[j], dp1[j]);}cout << dp[n];return 0; } 新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎!定制產(chǎn)品紅包拿不停!

    總結(jié)

    以上是生活随笔為你收集整理的信息学奥赛一本通 1844:【06NOIP提高组】金明的预算方案 | 洛谷 P1064 [NOIP2006 提高组] 金明的预算方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。