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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AcWing-算法提高课【合集】

發布時間:2023/12/14 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AcWing-算法提高课【合集】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

算法提高

  • 動態規劃
    • 數字三角形
      • 1015. 摘花生
      • 1018.最低通行費
      • 1027. 方格取數
    • 最長上升子序列LIS
      • 1017. 怪盜基德的滑翔翼
      • 1014.登山
      • 482.合唱隊形
      • 1012. 友好城市
      • 1016. 最大上升子序列和
      • 1010.攔截導彈
      • 187. 導彈防御系統
      • 272. 最長公共上升子序列
    • 背包
      • 423. 采藥
      • 1024. 裝箱問題
      • 1022. 寵物小精靈之收服
      • 6. 多重背包問題 III
      • 8. 二維費用的背包問題
      • 1020. 潛水員
      • 278. 數字組合
      • 1019. 慶功會
      • 1023. 買書
      • 12. 背包問題求具體方案
      • 1013. 機器分配
      • 487. 金明的預算方案
      • 426. 開心的金明
      • 1021. 貨幣系統
      • 532. 貨幣系統
      • 7. 混合背包問題
      • 10. 有依賴的背包問題
      • 11. 背包問題求方案數
      • 734. 能量石

優質寶藏題解

動態規劃

數字三角形

特征:
①從左上角到右下角
②走一條路或是n條路
③求最大值或最小值

1015. 摘花生

Hello Kitty想摘點花生送給她喜歡的米老鼠。

她來到一片有網格狀道路的矩形花生地(如下圖),從西北角進去,東南角出來。

地里每個道路的交叉點上都有種著一株花生苗,上面有若干顆花生,經過一株花生苗就能摘走該它上面所有的花生。

Hello Kitty只能向東或向南走,不能向西或向北走。

問Hello Kitty最多能夠摘到多少顆花生。

輸入格式
第一行是一個整數T,代表一共有多少組數據。
接下來是T組數據。
每組數據的第一行是兩個整數,分別代表花生苗的行數R和列數 C。
每組數據的接下來R行數據,從北向南依次描述每行花生苗的情況。每行數據有C個整數,按從西向東的順序描述了該行每株花生苗上的花生數目M。
輸出格式
對每組輸入數據,輸出一行,內容為Hello Kitty能摘到得最多的花生顆數。
數據范圍

1≤T≤100
1≤R,C≤100,
0≤M≤1000

輸入樣例:

2
2 2
1 1
3 4
2 3
2 3 4
1 6 5
輸出樣例:

8
16

簡記:(從1開始,求max) 最后一步劃分所有轉移情況:[i][j]為[i-1][j] 或 [i][j-1] 轉移(同時加每格子價值w[i][j])f[i][j] = max(f[i-1][j],f[i][j-1])+w[i][j];printf("%d", f[n][m] ) ; 下標從1開始 #include <iostream> #include <algorithm> //需記庫 using namespace std;const int N = 105;int n,m; int w[N][N],f[N][N];int main(){int T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);for(int i = 1;i <= n;i++)for(int j = 1;j <= m;j++)scanf("%d",&w[i][j]);for(int i = 1;i <= n;i++)for(int j = 1;j <= m;j++)f[i][j] = max(f[i-1][j],f[i][j-1])+w[i][j];printf("%d\n",f[n][m]);}return 0; }

1018.最低通行費


一個商人穿過一個 N×N 的正方形的網格,去參加一個非常重要的商務活動。
他要從網格的左上角進,右下角出。
每穿越中間 1 個小方格,都要花費 1 個單位時間。
商人必須在 (2N?1)個單位時間穿越出去。 【穿過邊長時耗時間1( 指左上走到右下的最小花費)】
而在經過中間的每個小方格時,都需要繳納一定的費用。
這個商人期望在規定時間內用最少費用穿越出去。
請問至少需要多少費用?
注意:不能對角穿越各個小方格(即,只能向上下左右四個方向移動且不能離開網格)。
輸入格式
第一行是一個整數,表示正方形的寬度 N。
后面 N 行,每行 N 個不大于 100 的正整數,為網格上每個小方格的費用。
輸出格式
輸出一個整數,表示至少需要的費用。
數據范圍
1≤N≤100

輸入樣例:
5
1 4 6 8 10
2 5 7 15 17
6 8 9 18 20
10 11 12 19 21
20 23 25 29 33

輸出樣例:
109

樣例解釋:
樣例中,最小值為 109=1+2+5+7+9+12+19+21+33。

簡記:(從1開始,求min【特判邊界均INF,導致無法更新最小值】,初始化INF = 0x3f3f3f3f )【公式:數字三角形】

數字三角形但屬性min-需特判邊界

數字三角形和摘花生初始化邊界就為0, 不影響max轉移判斷
此題與摘花生轉移方式相同【僅屬性不同:min】:邊界初始值為0,會影響第一行和列都變0:需解決【把邊界初始化INF】
總結:求min,但轉移過程用到邊界初始值0,第一行(列)會min變0

#include<cstdio> #include<algorithm>using namespace std;const int N = 110, INF = 0x3f3f3f3f;int w[N][N]; int f[N][N];int main() {int L;scanf("%d", &L); for(int i = 1; i <= L; i++)for(int j = 1; j <= L; j++)scanf("%d", &w[i][j]);for(int i = 1; i <= L; i++) //處理邊界初始INF,用到邊界轉移不影響第一行(列)f[0][i] = f[i][0] = INF;for(int i = 1; i <= L; i++)for(int j = 1; j <= L; j++) if(i == 1 && j == 1) f[i][j] = w[i][j]; //處理邊界 出發點的值固定先初始化: w[i][j]else f[i][j] = min(f[i][j - 1], f[i - 1][j]) + w[i][j];printf("%d\n", f[L][L]);return 0; }

y總判邊界:

#include<bits/stdc++.h>#include<algorithm> using namespace std;const int N = 110,INF = 1e9;int n; int w[N][N]; int f[N][N];int main() {scanf("%d",&n);for(int i = 1;i <= n;i++)for(int j = 1;j <= n;j++)scanf("%d",&w[i][j]);//f[i][0]和f[0][j] = 0 min判斷邊界會影響最小值【第一行或列會變成0】for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++)//因為從1開始,邊界判斷 if(i == 1 && j == 1) f[i][j] = w[i][j]; //特判左上角【出發點不需要轉移,固定值】 else{f[i][j] = INF;//邊初始值邊更新(導致下面分類,邊界f[0][第一列]=f[第一行][0] = 0)if(i > 1)f[i][j] = min(f[i][j],f[i - 1][j] + w[i][j]);//只有不在第一行的時候,才可以從上面過來 if(j > 1)f[i][j] = min(f[i][j],f[i][j - 1] + w[i][j]);//只有不在第一列的時候,才可以從左邊過來 }printf("%d\n",f[n][n]); return 0; }

1027. 方格取數

設有 N×N 的方格圖,我們在其中的某些方格中填入正整數,而其它的方格中則放入數字0。如下圖所示:

某人從圖中的左上角 A 出發,可以向下行走,也可以向右行走,直到到達右下角的 B 點。
在走過的路上,他可以取走方格中的數(取走后的方格中將變為數字0)。
此人從 A 點到 B 點共走了兩次,試找出兩條這樣的路徑,使得取得的數字和為最大。
輸入格式
第一行為一個整數N,表示 N×N 的方格圖。
接下來的每行有三個整數,第一個為行號數,第二個為列號數,第三個為在該行、該列上所放的數。
行和列編號從 1 開始。
一行“0 0 0”表示結束。
輸出格式
輸出一個整數,表示兩條路徑上取得的最大的和。
數據范圍
N < = 10

輸入樣例:
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0

輸出樣例:
67

(NOPI難度)
樸素:(1,1),(1,1)分別走到(i1,j1), (i2,j2)的路徑最大值 ,如何處理同一個格子不能被重復選擇 bool標記
只有在 i1+j1 == i2+ j2 時,兩條路徑才可能重合 (需保證有重合時,值只被計算一次)
f[k,i1,i2] 表示(1,1)—>(i1,k-i1) , (1,1)—>(i2,k-i2) 的max 【k表示兩條路徑當前走到的格子的橫縱坐標之和】
劃分:(右,下)*(右,下) : 四種選法 (走兩次:每個格子只能算一次值)

簡記:輸入:while(cin >> a >> b >> c, a|| b || c) w[a][b] = c;f[k,i1,i2] : 分重合 :w[i1,j1] ,不重合 :w[i1,j1] + w[i2,j2] (k 到2n ,i1到n,i2到n,三重遍歷)int j1 = k - i1,j2 = k - i2; 【在[1,n]內遍歷】int t = w[i1][j1];int &x = f[k][i1][i2]; //引用,用別名表示(太長了 !!!,把答案取個別名)if(i1 != i2) t+= w[i2][j2]; //不重復//枚舉四種方向分法(右,下)* (右,下)x = max(x,f[k-1][i1-1][i2-1] + t);x = max(x,f[k-1][i1][i2-1] + t);x = max(x,f[k-1][i1-1][i2-1] + t);x = max(x,f[k-1][i1][i2] + t); //兩條都往右 #include<bits/stdc++.h> #include<algorithm>using namespace std;const int N = 15;int n; int w[N][N]; int f[N*2][N][N];int main() {scanf("%d",&n);int a,b,c;while(cin >> a >> b >> c, a|| b || c) w[a][b] = c;for(int k = 2;k <= n+n;k++)for(int i1 = 1;i1 <= n;i1++)for(int i2 = 1;i2 <= n;i2++){int j1 = k - i1,j2 = k - i2;if(j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n){int t = w[i1][j1];int &x = f[k][i1][i2]; //引用,用別名表示(太長了 if(i1 != i2) t+= w[i2][j2]; //不重復//枚舉四種方向分法(右,下)* (右,下)x = max(x,f[k-1][i1-1][i2-1] + t);x = max(x,f[k-1][i1][i2-1] + t);x = max(x,f[k-1][i1-1][i2-1] + t);x = max(x,f[k-1][i1][i2] + t); //兩條都往右 }} printf("%d\n",f[n + n][n][n]); return 0; }

最長上升子序列LIS

895基礎題:
給定一個長度為 N 的數列,求數值嚴格單調遞增的子序列的長度最長是多少。

輸入格式
第一行包含整數 N。

第二行包含 N 個整數,表示完整序列。

輸出格式
輸出一個整數,表示最大長度。

數據范圍
1≤N≤1000,
?10 ^ 9≤數列中的數≤10 ^ 9

輸入樣例:
7
3 1 2 1 8 5 6

輸出樣例:
4

簡記:分類:算出以a[i] 結尾的LIS , 每個a[i]結尾的最大值存在f[i] 比較f不同結尾的LIS長度: res = max(res , f[i] ) i ∈[1,n]for(int i = 1;i <= n;i++){f[i] = 1;for(int j = 1;j < i;j ++) if(a[j] < a[i]) 一個比a[j] 大的值,比f[j]多了一個長度: a[i] 的max對應 f[i] f[i] = max(f[i] , f[j] + 1); }int res = 0;for(int i = 1;i <= n;i++) res = max(res,f[i]); #include<bits/stdc++.h>#include<algorithm> using namespace std;const int N = 1010;int n; int a[N],f[N]; int main() {scanf("%d",&n);for(int i = 1;i <= n;i++) scanf("%d",&a[i]); for(int i = 1;i <= n;i++){f[i] = 1;for(int j = 1;j < i;j ++)if(a[j] < a[i])f[i] = max(f[i] , f[j] + 1);}int res = 0;for(int i = 1;i <= n;i++) res = max(res,f[i]);printf("%d\n",res); return 0; }

1017. 怪盜基德的滑翔翼

怪盜基德是一個充滿傳奇色彩的怪盜,專門以珠寶為目標的超級盜竊犯。

而他最為突出的地方,就是他每次都能逃脫中村警部的重重圍堵,而這也很大程度上是多虧了他隨身攜帶的便于操作的滑翔翼。

有一天,怪盜基德像往常一樣偷走了一顆珍貴的鉆石,不料卻被柯南小朋友識破了偽裝,而他的滑翔翼的動力裝置也被柯南踢出的足球破壞了。

不得已,怪盜基德只能操作受損的滑翔翼逃脫。

假設城市中一共有N幢建筑排成一條線,每幢建筑的高度各不相同。

初始時,怪盜基德可以在任何一幢建筑的頂端。

他可以選擇一個方向逃跑,但是不能中途改變方向(因為中森警部會在后面追擊)。

因為滑翔翼動力裝置受損,他只能往下滑行(即:只能從較高的建筑滑翔到較低的建筑)。

他希望盡可能多地經過不同建筑的頂部,這樣可以減緩下降時的沖擊力,減少受傷的可能性。

請問,他最多可以經過多少幢不同建筑的頂部(包含初始時的建筑)?

輸入格式
輸入數據第一行是一個整數K,代表有K組測試數據。

每組測試數據包含兩行:第一行是一個整數N,代表有N幢建筑。第二行包含N個不同的整數,每一個對應一幢建筑的高度h,按照建筑的排列順序給出。

輸出格式
對于每一組測試數據,輸出一行,包含一個整數,代表怪盜基德最多可以經過的建筑數量。

數據范圍
1≤K≤100,
1≤N≤100,
0<h<10000
輸入樣例:
3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10
輸出樣例:
6
6
9

方向確定就只能往一個方向跳(左/右)
如圖:起點a[i] ,最長距離就是以a[i] 結尾的最長上升子序列
【圖形:先上升再下降(則右邊往左看為逆LIS ,左<—右 ,逆序LIS (起點n ,i- -,j- -))

簡記:(正向+反向求解LIS ,比較得max)逆序: 起點n ,i--,j-- ,i,j意義與正向一樣不變//不用res=0, 正反方向取max for(int i = n; i ;i--) //i > 0{f[i] = 1;for(int j = n;j > i;j --)if(a[i] > a[j])f[i] = max(f[i] , f[j] + 1); res = max(res,f[i]); //算出一個f[i]就比較一次 } #include<bits/stdc++.h>#include<algorithm> using namespace std;const int N = 1010;int n,T; int a[N],f[N]; int main() {int T;scanf("%d",&T);while(T--){scanf("%d",&n);for(int i = 1;i <= n;i++) scanf("%d",&a[i]); //正向求解LISint res = 0;for(int i = 1;i <= n;i++){f[i] = 1;for(int j = 1;j < i;j ++)if(a[j] < a[i])f[i] = max(f[i] , f[j] + 1); res = max(res,f[i]); //算出一個f[i]就比較一次 }//不用res=0, 正反方向取max for(int i = n; i ;i--) //i > 0{f[i] = 1;for(int j = n;j > i;j --)if(a[i] > a[j])f[i] = max(f[i] , f[j] + 1); res = max(res,f[i]); //算出一個f[i]就比較一次 }printf("%d\n",res); }return 0; }

1014.登山

題目描述:

五一到了,ACM隊組織大家去登山觀光,隊員們發現山上一個有N個景點,并且決定按照順序來瀏覽這些景點,即每次所瀏覽景點的編號都要大于前一個瀏覽景點的編號。

同時隊員們還有另一個登山習慣,就是不連續瀏覽海拔相同的兩個景點,并且一旦開始下山,就不再向上走了。

隊員們希望在滿足上面條件的同時,盡可能多的瀏覽景點,你能幫他們找出最多可能瀏覽的景點數么?

輸入格式

第一行包含整數N,表示景點數量。

第二行包含N個整數,表示每個景點的海拔。

輸出格式

輸出一個整數,表示最多能瀏覽的景點數。

數據范圍

2≤N≤1000

輸入樣例:

8
186 186 150 200 160 130 197 220
輸出樣例:

4

按編號遞增順序瀏覽 --> 必須是子序列
先嚴格上升再嚴格下降
一旦開始下降就不能上升了
分類:以a[k]為極值點(轉折)的子序列的max(正+反-1:有一個共同重疊點)

簡記: a[k]的max:上升存f[i],下降存g[i] ,res = max(res , f[i] + g[i] - 1) #include<bits/stdc++.h>#include<algorithm> using namespace std;const int N = 110;int n,T; int a[N]; int g[N],f[N]; int main() {scanf("%d",&n);for(int i = 1;i <= n;i++) scanf("%d",&a[i]); //正向求解LIS存到f[i] for(int i = 1;i <= n;i++){f[i] = 1;for(int j = 1;j < i;j ++)if(a[j] < a[i])f[i] = max(f[i] , f[j] + 1); }//反向求解LIS 存到g[i] for(int i = n;i;i--){g[i] = 1;for(int j = n;j > i;j--)if(a[i] > a[j])g[i] = max(g[i], g[j] + 1);} int res = 0;for(int i = 1;i <= n;i++) res = max(res , f[i] + g[i] - 1);printf("%d\n",res); return 0; }

482.合唱隊形

題目描述:

N位同學站成一排,音樂老師要請其中的(N-K)位同學出列,使得剩下的K位同學排成合唱隊形。

合唱隊形是指這樣的一種隊形:設K位同學從左到右依次編號為1,2…,K,他們的身高分別為T1,T2,…,TK,??則他們的身高滿足T1<…Ti+1>…>TK(1≤i≤K)。

你的任務是,已知所有N位同學的身高,計算最少需要幾位同學出列,可以使得剩下的同學排成合唱隊形。

輸入格式

輸入的第一行是一個整數N,表示同學的總數。

第二行有n個整數,用空格分隔,第i個整數Ti是第i位同學的身高(厘米)。

輸出格式

輸出包括一行,這一行只包含一個整數,就是最少需要幾位同學出列。

數據范圍

2≤N≤100,
130≤Ti≤230

輸入樣例:

8
186 186 150 200 160 130 197 220
輸出樣例:

4

最少去掉多少個能變成嚴格單調上升再下降 :
== 總人數 - (正向LIS+反向LIS) = (n - res ) = n(n - max(f[i]+g[i]-1))

簡記:(代碼和1014.登山一樣,僅輸出變成n-res) #include<bits/stdc++.h>#include<algorithm> using namespace std;const int N = 110;int n; int a[N]; int g[N],f[N]; int main() {scanf("%d",&n);for(int i = 1;i <= n;i++) scanf("%d",&a[i]); //正向求解LIS存到f[i] for(int i = 1;i <= n;i++){f[i] = 1;for(int j = 1;j < i;j ++)if(a[j] < a[i])f[i] = max(f[i] , f[j] + 1); }//反向求解LIS 存到g[i] for(int i = n;i;i--){g[i] = 1;for(int j = n;j > i;j--)if(a[i] > a[j])g[i] = max(g[i], g[j] + 1);} int res = 0;for(int i = 1;i <= n;i++) res = max(res , f[i] + g[i] - 1);printf("%d\n",n - res); return 0; }

1012. 友好城市

Palmia國有一條橫貫東西的大河,河有筆直的南北兩岸,岸上各有位置各不相同的N個城市。

北岸的每個城市有且僅有一個友好城市在南岸,而且不同城市的友好城市不相同。

每對友好城市都向政府申請在河上開辟一條直線航道連接兩個城市,但是由于河上霧太大,政府決定避免任意兩條航道交叉,以避免事故。

編程幫助政府做出一些批準和拒絕申請的決定,使得在保證任意兩條航線不相交的情況下,被批準的申請盡量多。

輸入格式
第1行,一個整數N,表示城市數。

第2行到第n+1行,每行兩個整數,中間用1個空格隔開,分別表示南岸和北岸的一對友好城市的坐標。

輸出格式
僅一行,輸出一個整數,表示政府所能批準的最多申請數。

數據范圍
1≤N≤5000,
0≤xi≤10000
輸入樣例:
7
22 4
2 6
10 3
15 12
9 8
17 17
4 2
輸出樣例:
4

自變量與因變量:x,y為一對友好城市坐標【對應的(x,y)才可建造一座橋
(先把一岸的x排序,然后遍歷對岸y的LIS ,即為res = max(res,y_LIS))

簡記:先坐標排序PII q : q[i].first = x (編號排序) , q[i].second = y (值比較) 下標從0開始 可以直接 : sort(q, q+ n) 按q[i].first 排序 #include<bits/stdc++.h>#include<algorithm> using namespace std;typedef pair<int ,int > PII; const int N = 5010;int n; PII q[N]; //坐標(x,y) [編號排序,值比較] int f[N];int main() {scanf("%d",&n);for(int i = 0;i < n;i++) scanf("%d%d",&q[i].first,&q[i].second); sort(q,q+n); //默認first,橫坐標排序 [縱坐標為值] int res = 0;for(int i = 0;i < n;i++){f[i] = 1;for(int j = 0;j < i;j++)if(q[i].second > q[j].second)f[i] = max(f[i], f[j] + 1);res = max( res , f[i]); } printf("%d\n",res); return 0; }

1016. 最大上升子序列和

一個數的序列 bi,當 b1<b2<…<bS 的時候,我們稱這個序列是上升的。

對于給定的一個序列(a1,a2,…,aN),我們可以得到一些上升的子序列(ai1,ai2,…,aiK),這里1≤i1<i2<…<iK≤N。

比如,對于序列(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7),(3,4,8)等等。

這些子序列中和最大為18,為子序列(1,3,5,9)的和。

你的任務,就是對于給定的序列,求出最大上升子序列和。

注意,最長的上升子序列的和不一定是最大的,比如序列(100,1,2,3)的最大上升子序列和為100,而最長上升子序列為(1,2,3)。

輸入格式
輸入的第一行是序列的長度N。

第二行給出序列中的N個整數,這些整數的取值范圍都在0到10000(可能重復)。

輸出格式
輸出一個整數,表示最大上升子序列和。

數據范圍
1≤N≤1000
輸入樣例:
7
1 7 3 5 9 4 8
輸出樣例:
18

簡記:(LIS算法 ,把f[j]+1改成 f[j]+ a[i] 就可求子序列和的最大值) #include<bits/stdc++.h>#include<algorithm> using namespace std;const int N = 1010;int n; int a[N]; int f[N]; int main() {scanf("%d",&n);for(int i = 1;i <= n;i++) scanf("%d",&a[i]); //正向求解LIS存到f[i] for(int i = 1;i <= n;i++){f[i] = 1;for(int j = 1;j < i;j ++)if(a[j] < a[i])f[i] = max(f[i] , f[j] + a[i]); }int res = 0;for(int i = 1;i <= n;i++) res = max(res , f[i]);printf("%d\n",n - res); return 0; }

1010.攔截導彈

某國為了防御敵國的導彈襲擊,發展出一種導彈攔截系統。

但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以后每一發炮彈都不能高于前一發的高度。

某天,雷達捕捉到敵國的導彈來襲。

由于該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈。

輸入導彈依次飛來的高度(雷達給出的高度數據是不大于30000的正整數,導彈數不超過1000),計算這套系統最多能攔截多少導彈,如果要攔截所有導彈最少要配備多少套這種導彈攔截系統。

輸入格式
共一行,輸入導彈依次飛來的高度。

輸出格式
第一行包含一個整數,表示最多能攔截的導彈數。

第二行包含一個整數,表示要攔截所有導彈最少要配備的系統數。

數據范圍
雷達給出的高度數據是不大于 30000 的正整數,導彈數不超過 1000。

輸入樣例:
389 207 155 300 299 170 158 65 【加點才結束…】

輸出樣例:
6
2

思路:hhh

#include<bits/stdc++.h>#include<algorithm> using namespace std;const int N = 1010;int n; int q[N]; //a[i] int f[N],g[N]; int main() {while( cin >> q[n] ) n++;int res = 0;for(int i = 0;i < n;i++){f[i] = 1;for(int j = 0;j < i;j ++)if(q[j] >= q[i])f[i] = max(f[i] , f[j] + 1); res = max(res ,f[i]);}printf("%d\n",res); int cnt = 0;for(int i = 0;i < n; i++){int k = 0;while(k < cnt && g[k] < q[i]) k++;g[k]=q[i];if(k >= cnt) cnt++;}printf("%d\n",cnt); return 0; }

187. 導彈防御系統

為了對抗附近惡意國家的威脅,R 國更新了他們的導彈防御系統。

一套防御系統的導彈攔截高度要么一直 嚴格單調 上升要么一直 嚴格單調 下降。

例如,一套系統先后攔截了高度為 3 和高度為 4 的兩發導彈,那么接下來該系統就只能攔截高度大于 4 的導彈。

給定即將襲來的一系列導彈的高度,請你求出至少需要多少套防御系統,就可以將它們全部擊落。

輸入格式
輸入包含多組測試用例。

對于每個測試用例,第一行包含整數 n,表示來襲導彈數量。

第二行包含 n 個不同的整數,表示每個導彈的高度。

當輸入測試用例 n=0 時,表示輸入終止,且該用例無需處理。

輸出格式
對于每個測試用例,輸出一個占據一行的整數,表示所需的防御系統數量。

數據范圍
1≤n≤50
輸入樣例:
5
3 5 2 4 1
0
輸出樣例:
2
樣例解釋
對于給出樣例,最少需要兩套防御系統。

一套擊落高度為 3,4 的導彈,另一套擊落高度為 5,2,1 的導彈。

貪心
選擇1:接在現有的某個子序列之后
選擇2:創建1個新的系統
解釋(代碼java):min(上升+下降 的LIS數量)

272. 最長公共上升子序列

熊大媽的奶牛在小沐沐的熏陶下開始研究信息題目。

小沐沐先讓奶牛研究了最長上升子序列,再讓他們研究了最長公共子序列,現在又讓他們研究最長公共上升子序列了。

小沐沐說,對于兩個數列 A 和 B,如果它們都包含一段位置不一定連續的數,且數值是嚴格遞增的,那么稱這一段數是兩個數列的公共上升子序列,而所有的公共上升子序列中最長的就是最長公共上升子序列了。

奶牛半懂不懂,小沐沐要你來告訴奶牛什么是最長公共上升子序列。

不過,只要告訴奶牛它的長度就可以了。

數列 A 和 B 的長度均不超過 3000。

輸入格式
第一行包含一個整數 N,表示數列 A,B 的長度。

第二行包含 N 個整數,表示數列 A。

第三行包含 N 個整數,表示數列 B。

輸出格式
輸出一個整數,表示最長公共上升子序列的長度。

數據范圍
1≤N≤3000,序列中的數字均不超過 231?1。

輸入樣例:
4
2 2 1 3
2 1 2 3
輸出樣例:
2

背包

423. 采藥

辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。

為此,他想拜附近最有威望的醫師為師。

醫師為了判斷他的資質,給他出了一個難題。

醫師把他帶到一個到處都是草藥的山洞里對他說:“孩子,這個山洞里有一些不同的草藥,采每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間里,你可以采到一些草藥。如果你是一個聰明的孩子,你應該可以讓采到的草藥的總價值最大。”

如果你是辰辰,你能完成這個任務嗎?

輸入格式
輸入文件的第一行有兩個整數T和M,用一個空格隔開,T代表總共能夠用來采藥的時間,M代表山洞里的草藥的數目。

接下來的M行每行包括兩個在1到100之間(包括1和100)的整數,分別表示采摘某株草藥的時間和這株草藥的價值。

輸出格式
輸出文件包括一行,這一行只包含一個整數,表示在規定的時間內,可以采到的草藥的最大總價值。

數據范圍
1≤T≤1000,
1≤M≤100
輸入樣例:
70 3
71 100
69 1
1 2
輸出樣例:
3

1024. 裝箱問題

有一個箱子容量為V ,同時有n 個物品,每個物品有一個體積(正整數)。要求n 個物品中,任取若干個裝入箱內,使箱子的剩余空間為最小。

輸入格式:
第一行是一個整數V ,表示箱子容量。第二行是一個整數n ,表示物品數。接下來n 行,每行一個正整數(不超過10000 ),分別表示這n 個物品的各自體積。

輸出格式:
一個整數,表示箱子剩余空間。

數據范圍:
0 < V ≤ 20000
0 < n ≤ 30

1022. 寵物小精靈之收服

寵物小精靈是一部講述小智和他的搭檔皮卡丘一起冒險的故事。

一天,小智和皮卡丘來到了小精靈狩獵場,里面有很多珍貴的野生寵物小精靈。

小智也想收服其中的一些小精靈。

然而,野生的小精靈并不那么容易被收服。

對于每一個野生小精靈而言,小智可能需要使用很多個精靈球才能收服它,而在收服過程中,野生小精靈也會對皮卡丘造成一定的傷害(從而減少皮卡丘的體力)。

當皮卡丘的體力小于等于0時,小智就必須結束狩獵(因為他需要給皮卡丘療傷),而使得皮卡丘體力小于等于0的野生小精靈也不會被小智收服。

當小智的精靈球用完時,狩獵也宣告結束。

我們假設小智遇到野生小精靈時有兩個選擇:收服它,或者離開它。

如果小智選擇了收服,那么一定會扔出能夠收服該小精靈的精靈球,而皮卡丘也一定會受到相應的傷害;如果選擇離開它,那么小智不會損失精靈球,皮卡丘也不會損失體力。

小智的目標有兩個:主要目標是收服盡可能多的野生小精靈;如果可以收服的小精靈數量一樣,小智希望皮卡丘受到的傷害越小(剩余體力越大),因為他們還要繼續冒險。

現在已知小智的精靈球數量和皮卡丘的初始體力,已知每一個小精靈需要的用于收服的精靈球數目和它在被收服過程中會對皮卡丘造成的傷害數目。

請問,小智該如何選擇收服哪些小精靈以達到他的目標呢?

輸入格式
輸入數據的第一行包含三個整數:N,M,K,分別代表小智的精靈球數量、皮卡丘初始的體力值、野生小精靈的數量。

之后的K行,每一行代表一個野生小精靈,包括兩個整數:收服該小精靈需要的精靈球的數量,以及收服過程中對皮卡丘造成的傷害。

輸出格式
輸出為一行,包含兩個整數:C,R,分別表示最多收服C個小精靈,以及收服C個小精靈時皮卡丘的剩余體力值最多為R。

數據范圍
0<N≤1000,
0<M≤500,
0<K≤100

輸入樣例1:
10 100 5
7 10
2 40
2 50
1 20
4 20

輸出樣例1:
3 30

6. 多重背包問題 III

有 N 種物品和一個容量是 V 的背包。

第 i 種物品最多有 si 件,每件體積是 vi,價值是 wi。

求解將哪些物品裝入背包,可使物品體積總和不超過背包容量,且價值總和最大。
輸出最大價值。

####輸入格式
第一行兩個整數,N,V (0<N≤1000, 0<V≤20000),用空格隔開,分別表示物品種數和背包容積。

接下來有 N 行,每行三個整數 vi,wi,si,用空格隔開,分別表示第 i 種物品的體積、價值和數量。

輸出格式
輸出一個整數,表示最大價值。

數據范圍
0<N≤1000
0<V≤20000
0<vi,wi,si≤20000
提示
本題考查多重背包的單調隊列優化方法。

輸入樣例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
1
2
3
4
5
輸出樣例:
10

8. 二維費用的背包問題

每件物品只能用一次。體積是 vi,重量是 mi,價值是 wi。

求解將哪些物品裝入背包,可使物品總體積不超過背包容量,總重量不超過背包可承受的最大重量,且價值總和最大。
輸出最大價值。

輸入格式
第一行三個整數,N,V,M,用空格隔開,分別表示物品件數、背包容積和背包可承受的最大重量。

接下來有 N 行,每行三個整數 vi,mi,wi,用空格隔開,分別表示第 i 件物品的體積、重量和價值。

輸出格式
輸出一個整數,表示最大價值。

數據范圍
0<N≤1000
0<V,M≤100
0<vi,mi≤100
0<wi≤1000

輸入樣例
4 5 6
1 2 3
2 4 4
3 4 5
4 5 6

輸出樣例:
8

簡記:01 背包+重量限制,再多開一維加優化:f[j][k] = max (f[j - v[i]][k - m[i]] + w[i], f[j][k]); 滿足兩個限制,V,M均從大往小開始轉移 // 01 背包+重量限制,再多開一維。 //即三維,同01背包壓縮優化成二維#include <bits/stdc++.h> using namespace std;const int N = 1e3 + 10;int n, V, M; //種類,體積,重量 int v[N], m[N], w[N], f[N][N]; int main () {cin >> n >> V >> M;for (int i = 1; i <= n; i ++) {cin >> v[i] >> m[i] >> w[i];//體積,重量,價值}for (int i = 1; i <= n; i ++)for (int j = V; j >= v[i]; j --) //均從大往小開始轉移for (int k = M; k >= m[i]; k --)f[j][k] = max (f[j - v[i]][k - m[i]] + w[i], f[j][k]);//兩個限制均要滿足cout << f[V][M];return 0; }

1020. 潛水員

潛水員為了潛水要使用特殊的裝備。

他有一個帶2種氣體的氣缸:一個為氧氣,一個為氮氣。【價值1,價值2】

讓潛水員下潛的深度需要各種數量的氧和氮。

潛水員有一定數量的氣缸。

每個氣缸都有重量和氣體容量。

潛水員為了完成他的工作需要特定數量的氧和氮。

他完成工作所需氣缸的總重的最低限度的是多少?

例如:潛水員有5個氣缸。每行三個數字為:氧,氮的(升)量和氣缸的重量:

3 36 120

10 25 129

5 50 250

1 45 130

4 20 119
如果潛水員需要5升的氧和60升的氮則總重最小為249(1,2或者4,5號氣缸)。

你的任務就是計算潛水員為了完成他的工作需要的氣缸的重量的最低值。

輸入格式
第一行有2個整數 m,n。它們表示氧,氮各自需要的量。

第二行為整數 k 表示氣缸的個數。

此后的 k 行,每行包括ai,bi,ci,3個整數。這些各自是:第 i 個氣缸里的氧和氮的容量及氣缸重量。

輸出格式
僅一行包含一個整數,為潛水員完成工作所需的氣缸的重量總和的最低值。

數據范圍
1≤m≤21,
1≤n≤79,
1≤k≤1000,
1≤ai≤21,
1≤bi≤79,
1≤ci≤800
輸入樣例:
5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
輸出樣例:
249

輸入樣例:
5 60
5
21 1 120
21 50 129
21 5 250
21 2 130
21 2 119
輸出樣例:
249
簡記:f[i][j] = min(f[i][j] , f[i - v1][ j- v2 ] + w); 【 至少是n,m ,可以大于】
求min 可以 res = 0x3f3f3f3f ,memset(f , 0x3f,sizeof f);

#include<bits/stdc++.h> using namespace std;const int N = 22 , M = 80; int n,m,k; int f[N][M];int main() {cin >> n >> m >> k;memset(f,0x3f,sizeof f);f[0][0] = 0;while(k --){int v1,v2,w;cin >> v1 >> v2 >> w;for(int i = n; i >= 0; i--)//數組開了N個,從N開始就越界了 for(int j = m;j >= 0; j--)f[i][j] = min(f[i][j] , f[max(0,i - v1)][max(0,j- v2) ] + w);}int res = 1e9;//接近int_max 【有解,取個較大的數,否則也可以0x3f3f3f3f】for(int i = n;i < N;i++)for(int j = m;j < M;j ++)res = min(res ,f[i][j]);cout << res << endl; return 0; }

278. 數字組合

給定 N 個正整數 A1,A2,…,AN,從中選出若干個數,使它們的和為 M,求有多少種選擇方案。

輸入格式
第一行包含兩個整數 N 和 M。

第二行包含 N 個整數,表示 A1,A2,…,AN。

輸出格式
包含一個整數,表示可選方案數。

數據范圍
1≤N≤100,
1≤M≤10000,
1≤Ai≤1000,
答案保證在 int 范圍內。

輸入樣例:
4 4
1 1 2 2
輸出樣例:
3

思路: 只能選一次,所以子狀態必須是沒用選過的,所以必須逆序找沒有更新過的子狀態。

所有只從前個i物品選,且體積恰好是j的方案的集合
分類:包含物品i的所有選法(有就加一個對應價值為vi)
不包含物品i的所有選法(沒有vi就已經放滿)
f[i,j] = f[i-1,j-vi] + f[i-1,j]

#include <cstring> #include <iostream> #include <algorithm>using namespace std;const int N = 10010;int n, m; int f[N];int main() {cin >> n >> m;//種類,體積f[0] = 1;for (int i = 0; i < n; i ++ ){int v;cin >> v;for (int j = m; j >= v; j -- ) f[j] += f[j - v];}cout << f[m] << endl;return 0; }

1019. 慶功會

為了慶賀班級在校運動會上取得全校第一名成績,班主任決定開一場慶功會,為此撥款購買獎品犒勞運動員。

期望撥款金額能購買最大價值的獎品,可以補充他們的精力和體力。

輸入格式
第一行二個數n,m,其中n代表希望購買的獎品的種數,m表示撥款金額。

接下來n行,每行3個數,v、w、s,分別表示第I種獎品的價格、價值(價格與價值是不同的概念)和能購買的最大數量(買0件到s件均可)。

輸出格式
一行:一個數,表示此次購買能獲得的最大的價值(注意!不是價格)。

數據范圍
n≤500,m≤6000,
v≤100,w≤1000,s≤10
輸入樣例:
5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1
輸出樣例:
1040
多重背包模板
簡記:數據范圍小,不用拆成01 【多重背包模板】
f[j] = max(f[j] , f[j - k * v ] + k * w);

#include <bits/stdc++.h> using namespace std;const int N = 1e4 + 5; int n,m; int f[N];int main() {cin>>n>>m;while(n--){int v , w ,s;cin>>v>>w>>s;for(int j = m;j >= 0;j --)for(int k = 0;k <= s && k * v <= j;k ++)f[j] = max(f[j] , f[j - k * v ] + k * w); }cout << f[m] << endl;return 0; }

思路
多重背包問題:每種物品可用s次
背包的總體積V: 撥款金額m
物品的種數N:獎品的種數n
每種物品的價值w:該獎品的價值
每種物品的體積v:該獎品的價格
狀態表示:f[i][j]:只從前i個物品中選,且總體積不超過j的所有選法集合的最大值
狀態計算:f[i][j]=max(f[i][j],f[i-1][j-kv]+kw)
在能裝下的情況下每種物品可以選0次,1次,2次,,,k次
由于數據范圍較小,所以不需要進行二進制,或單調隊列優化
時間復雜度 O(nms) 大約為 3e7
這里將二維優化到了一維。

1023. 買書

  • 問題描述:
  • 小明手里有n元錢全部用來買書,書的價格為10元,20元,50元,100元。問小明有多少種買書方案?(每種書可購買多本)

    輸入格式

    一個整數 n,代表總共錢數。

    輸出格式

    一個整數,代表選擇方案種數。

    數據范圍
    0 ≤ n ≤ 1000

    輸入樣例1:
    20
    輸出樣例1:
    2
    輸入樣例2:
    15
    輸出樣例2:
    0
    輸入樣例3:
    0
    輸出樣例3:
    1

    完全背包:只從前i個物品選,且總體積恰好是j的方案的集合
    屬性count (數量)

    簡記:一維優化 f[j] +=f[j - v[i]] #include <bits/stdc++.h> using namespace std;const int N = 1010;int v[4] = {10,20,50,100}; //書價格 ,下標從0開始 int f[N];int main() {int m; //體積 cin >> m;f[0] = 1;for(int i = 0;i <= 4;i++) //種類 for(int j = v[i];j <= m;j++) f[j] += f[j-v[i]]; //一維優化后,恒等式可去 f[j] = f[j];cout << f[m] << endl;return 0; } 樸素: //樸素 #include <bits/stdc++.h> using namespace std;const int N = 1010;int v[] = {0,10,20,50,100}; //書價格 ,i種類下標從1開始 int f[N][N];int main() {int m; //體積 cin >> m;f[0][0] = 1;for(int i = 1;i <= 4;i++) //種類 for(int j = 0;j <= m;j++) {f[i][j] = f[i-1][j];if(j >= v[i]) f[i][j] += f[i][j-v[i]]; }//f[j] = max(f[j] , f[j - v[i]] ); cout << f[4][m] << endl;return 0; }

    12. 背包問題求具體方案

    有 N 件物品和一個容量是 V 的背包。每件物品只能使用一次。

    第 i 件物品的體積是 vi,價值是 wi。

    求解將哪些物品裝入背包,可使這些物品的總體積不超過背包容量,且總價值最大。

    輸出 字典序最小的方案。這里的字典序是指:所選物品的編號所構成的序列。物品的編號范圍是 1…N。

    輸入格式
    第一行兩個整數,N,V,用空格隔開,分別表示物品數量和背包容積。

    接下來有 N 行,每行兩個整數 vi,wi,用空格隔開,分別表示第 i 件物品的體積和價值。

    輸出格式
    輸出一行,包含若干個用空格隔開的整數,表示最優解中所選物品的編號序列,且該編號序列的字典序最小。

    物品編號范圍是 1…N。

    數據范圍
    0<N,V≤1000
    0<vi,wi≤1000

    輸入樣例
    4 5
    1 2
    2 4
    3 4
    4 6

    輸出樣例:
    1 4

    字典序最小–>貪心:體積從后往前盡量多選擇(多放)字典序(編號)小的
    可選可不選(一定要選)
    【若從后往前,則后面字典序大的可不選】

    #include<bits/stdc++.h> using namespace std;const int N = 1010;int n,m; int v[N],w[N]; int f[N][N];int main() {cin >> n >> m;for(int i = 1;i <= n;i++) cin >> v[i] >> w[i];for(int i = n;i >= 1;i--){for(int j = 0;j <= m;j++){f[i][j] = f[i+1][j];if(j >= v[i]) f[i][j] = max(f[i][j] ,f[i+1][j - v[i]] + w[i]);}} //f[1][m] 是最大價值 --》字典序最小的最大價值 int j = m;for(int i = 1;i <= n;i++)if(j >= v[i] && f[i][j] == f[i+1][j - v[i]] + w[i]){cout << i <<" ";j -= v[i];}return 0; }

    1013. 機器分配

    總公司擁有M臺 相同 的高效設備,準備分給下屬的N個分公司。

    各分公司若獲得這些設備,可以為國家提供一定的盈利。盈利與分配的設備數量有關。

    問:如何分配這M臺設備才能使國家得到的盈利最大?

    求出最大盈利值。

    分配原則:每個公司有權獲得任意數目的設備,但總臺數不超過設備數M。

    輸入格式
    第一行有兩個數,第一個數是分公司數N,第二個數是設備臺數M;

    接下來是一個N*M的矩陣,矩陣中的第 i 行第 j 列的整數表示第 i 個公司分配 j 臺機器時的盈利。

    輸出格式
    第一行輸出最大盈利值;

    接下N行,每行有2個數,即分公司編號和該分公司獲得設備臺數。

    答案不唯一,輸出任意合法方案即可。

    數據范圍
    1≤N≤10,
    1≤M≤15

    輸入樣例:
    3 3
    30 40 50
    20 30 50
    20 25 30

    輸出樣例:
    70
    1 1
    2 1
    3 1

    分組背包問題:按公司分組
    體積限制臺數

    #include<bits/stdc++.h> using namespace std;const int N = 11,M = 16;int n,m;//組,體積(總臺數) int w[N][M];//第i家公司,的第k件物品價值 int f[N][M];//價值 int way[N]; //記錄最大價值對應的kint main() {cin >> n >> m;for(int i = 1;i <= n;i++) for(int j = 1;j <= m;j++)cin >> w[i][j];for(int i = 1;i <= n;i++) for(int j = 0;j <= m;j++) //這里合并了f[i][j] = f[i-1][j] ; if(j>=w[i][k]) for(int k = 0;k <= j;k ++)f[i][j] = max(f[i][j] , f[i - 1][j - k] + w[i][k]); //f[j] = max(f[j] , f[j - k] + w[k]); ,但要寫出方案(每個公司臺數,用二維 cout << f[n][m] << endl;int j = m; //選m臺時取最大價值 for(int i = n ;i >= 0;i--)for(int k = 0;k <= j;k++)if(f[i][j] == f[i - 1][j - k] +w[i][k] ) //找到轉移的來源:k臺 {way[i] = k;j -= k; //剩下可分配 break;}//依題意輸出 for(int i = 1;i <= n ; i++) cout << i << " " << way[i] << endl;return 0; }

    487. 金明的預算方案

    金明今天很開心,家里購置的新房就要領鑰匙了,新房里有一間金明自己專用的很寬敞的房間。

    更讓他高興的是,媽媽昨天對他說:“你的房間需要購買哪些物品,怎么布置,你說了算,只要不超過N元錢就行”。

    今天一早,金明就開始做預算了,他把想買的物品分為兩類:主件與附件,附件是從屬于某個主件的,下表就是一些主件與附件的例子:

    如果要買歸類為附件的物品,必須先買該附件所屬的主件。

    每個主件可以有0個、1個或2個附件。

    附件不再有從屬于自己的附件。

    金明想買的東西很多,肯定會超過媽媽限定的N元。

    于是,他把每件物品規定了一個重要度,分為5等:用整數1~5表示,第5等最重要。

    他還從因特網上查到了每件物品的價格(都是10元的整數倍)。

    他希望在不超過N元(可以等于N元)的前提下,使每件物品的價格與重要度的乘積的總和最大。

    設第j件物品的價格為v[j],重要度為w[j],共選中了k件物品,編號依次為j1,j2,…,jk,則所求的總和為:

    v[j1]?w[j1]+v[j2]?w[j2]+…+v[jk]?w[jk](其中*為乘號)

    請你幫助金明設計一個滿足要求的購物單。

    輸入格式
    輸入文件的第1行,為兩個正整數,用一個空格隔開:N m,其中N表示總錢數,m為希望購買物品的個數。

    從第2行到第m+1行,第j行給出了編號為j-1的物品的基本數據,每行有3個非負整數v p q,其中v表示該物品的價格,p表示該物品的重要度(1~5),q表示該物品是主件還是附件。

    如果q=0,表示該物品為主件,如果q>0,表示該物品為附件,q是所屬主件的編號。

    輸出格式
    輸出文件只有一個正整數,為不超過總錢數的物品的價格與重要度乘積的總和的最大值(<200000)。

    數據范圍
    N<32000,m<60,v<10000
    輸入樣例:
    1000 5
    800 2 0
    400 5 1
    300 5 1
    400 3 0
    500 2 0
    輸出樣例:
    2200

    #include<bits/stdc++.h> //分組背包 主件和附件分成一個組(附件數量分類) #include <vector> using namespace std;typedef pair<int, int> PII;const int N = 70, M = 32010;int n, m; // 中n表示總錢數,m為希望購買物品的個數PII master[N];// {主件的價值 , 重要度*價值 } vector<PII> servant[N];//附件 int f[M];int main() {cin >> m >> n;for (int i = 1; i <= n; i++) {int v, w, q;cin >> v >> w >> q;if (!q) master[i] = {v, v * w}; // q=0,物品為主件else servant[q].push_back({v, v * w}); // 否則是附件,價格是v,權重*價值為v * w}// 0-1背包模板 for (int i = 1; i <= n; i++) for (int j = m; j >= 0; j--) {auto &sv = servant[i];// 枚舉所有附件的搭配情況,用狀態壓縮的辦法枚舉for (int k = 0; k < 1 << sv.size(); k++) {int v = master[i].first, w = master[i].second; //主件體積,價值 for (int u = 0; u < sv.size(); u++)if (k >> u & 1) //二進制優化轉換為01背包 {v += sv[u].first;w += sv[u].second;}if (j >= v) f[j] = max(f[j], f[j - v] + w);}}cout << f[m] << endl;return 0; }

    426. 開心的金明

    題目描述
    金明今天很開心,家里購置的新房就要領鑰匙了,新房里有一間他自己專用的很寬敞的房間。

    更讓他高興的是,媽媽昨天對他說:“你的房間需要購買哪些物品,怎么布置,你說了算,只要不超過N元錢就行”。

    今天一早金明就開始做預算,但是他想買的東西太多了,肯定會超過媽媽限定的N元。

    于是,他把每件物品規定了一個重要度,分為5等:用整數1~5表示,第5等最重要。

    他還從因特網上查到了每件物品的價格(都是整數元)。

    他希望在不超過N元(可以等于N元)的前提下,使每件物品的價格與重要度的乘積的總和最大。

    設第j件物品的價格為v[j],重要度為w[j],共選中了k件物品,編號依次為j1,j2,…,jk,則所求的總和為:

    v[j1]?w[j1]+v[j2]?w[j2]+…+v[jk]?w[jk]
    請你幫助金明設計一個滿足要求的購物單。

    輸入格式
    輸入文件的第1行,為兩個正整數N和m,用一個空格隔開。(其中N表示總錢數,m為希望購買物品的個數)

    從第2行到第m+1行,第j行給出了編號為j-1的物品的基本數據,每行有2個非負整數v和p。(其中v表示該物品的價格,p表示該物品的重要度)

    輸出格式
    輸出文件只有一個正整數,為不超過總錢數的物品的價格與重要度乘積的總和的最大值(數據保證結果不超過100000000)。

    數據范圍
    1≤N<30000,
    1≤m<25,
    0≤v≤10000,
    1≤p≤5

    輸入樣例:

    1000 5
    800 2
    400 5
    300 5
    400 3
    200 2

    輸出樣例:

    3900

    #include<bits/stdc++.h> using namespace std;const int N = 30010, M = 30;int n, m;//n種類,體積(最高可承受預算) int v, w;//v價值、w權重 int f[N];//最大價值 int main() {cin >> m >> n;for(int i = 1; i <= n; i ++) //從1開始 {cin >> v >> w;for(int j = m; j >= v; j --) f[j] = max(f[j], f[j - v] + w * v); //加對應權重值 w*v }cout << f[m] << endl;return 0; }

    1021. 貨幣系統

    給你一個n種面值的貨幣系統,求組成面值為m的貨幣有多少種方案。

    輸入格式
    第一行,包含兩個整數n和m。

    接下來n行,每行包含一個整數,表示一種貨幣的面值。

    輸出格式
    共一行,包含一個整數,表示方案數。

    數據范圍
    n≤15,m≤3000
    輸入樣例:
    3 10
    1
    2
    5
    輸出樣例:
    10

    (與1023.買書那叫一個一模一樣)

    簡記:f[i,j] = max(f[i-1,j] , f[i-1,j-vi]) 選i/不選i 到達j體積包含前i個物品【完全背包】一維優化:for(int j = a;j <= m;j++) f[j] += f[j - a]; #include<bits/stdc++.h> using namespace std;typedef long long ll;const int N = 3010;int n,m; int f[N];int main() {cin >> n>> m;f[0] = 1; //不選也是1種方案 for(int i = 0;i < n;i++){int a;cin >> a;for(int j = a;j <= m;j++) f[j] += f[j - a];}cout << f[m] << endl;return 0; }

    532. 貨幣系統

    在網友的國度中共有?n?種不同面額的貨幣,第?i?種貨幣的面額為?a[i],你可以假設每一種貨幣都有無窮多張。

    為了方便,我們把貨幣種數為?n、面額數組為?a[1…n]?的貨幣系統記作?(n,a)。

    在一個完善的貨幣系統中,每一個非負整數的金額?x?都應該可以被表示出,即對每一個非負整數?x,都存在?n?個非負整數?t[i]?滿足?a[i]×t[i]?的和為?x。

    然而,在網友的國度中,貨幣系統可能是不完善的,即可能存在金額?x?不能被該貨幣系統表示出。

    例如在貨幣系統?n=3,?a=[2,5,9]?中,金額?1,3?就無法被表示出來。

    兩個貨幣系統?(n,a)?和?(m,b)?是等價的,當且僅當對于任意非負整數?x,它要么均可以被兩個貨幣系統表出,要么不能被其中任何一個表出。

    現在網友們打算簡化一下貨幣系統。

    他們希望找到一個貨幣系統?(m,b),滿足?(m,b)?與原來的貨幣系統?(n,a)?等價,且?m?盡可能的小。

    他們希望你來協助完成這個艱巨的任務:找到最小的?m。

    輸入格式
    輸入文件的第一行包含一個整數?T,表示數據的組數。

    接下來按照如下格式分別給出 T 組數據。

    每組數據的第一行包含一個正整數?n。

    接下來一行包含?n?個由空格隔開的正整數?a[i]。

    輸出格式
    輸出文件共有 T 行,對于每組數據,輸出一行一個正整數,表示所有與?(n,a)?等價的貨幣系統?(m,b)?中,最小的?m。

    數據范圍
    1≤n≤100,
    1≤a[i]≤25000,
    1≤T≤20
    輸入樣例:

    2
    4
    3 19 10 6
    5
    11 29 13 19 17

    輸出樣例:

    2
    5

    性質1:a1 ,a2 ,…,an 一定可以被表示出來
    性質2:在最優解中,b1,b2,…,bm一定都是從a1,a2,…,an中選擇的
    性質3: b1,b2…,bm一定不能被其他bi 表示出來

    typedef long long ll;const int N = 110,M = 25010;int n; int a[N]; int f[M];int main() {int T;cin >> T;while(T--){cin >> n;for(int i = 0;i < n;i++) cin >> a[i];sort(a,a + n);int m = a[n - 1]; //遍歷到最大的數 memset(f , 0 , sizeof f);f[0] = 1; int res = 0;for(int i = 0;i < n;i++){if(!f[a[i]]) res ++;for(int j = a[i]; j <= m;j ++) //m = a[n - 1]f[j] += f[j - a[i]];} cout << res << endl;}return 0; }

    7. 混合背包問題

    有 N 種物品和一個容量是 V 的背包。

    物品一共有三類:

    第一類物品只能用1次(01背包);
    第二類物品可以用無限次(完全背包);
    第三類物品最多只能用 si 次(多重背包);
    每種體積是 vi,價值是 wi。

    求解將哪些物品裝入背包,可使物品體積總和不超過背包容量,且價值總和最大。
    輸出最大價值。

    輸入格式
    第一行兩個整數,N,V,用空格隔開,分別表示物品種數和背包容積。

    接下來有 N 行,每行三個整數 vi,wi,si,用空格隔開,分別表示第 i 種物品的體積、價值和數量。

    si=?1 表示第 i 種物品只能用1次;
    si=0 表示第 i 種物品可以用無限次;
    si>0 表示第 i 種物品可以使用 si 次;
    輸出格式
    輸出一個整數,表示最大價值。

    數據范圍
    0<N,V≤1000
    0<vi,wi≤1000
    ?1≤si≤1000
    輸入樣例
    4 5
    1 2 -1
    2 4 1
    3 4 0
    4 5 2
    輸出樣例:
    8

    01/多重/完全 【均為:只從前i件物品中選,且總體積不超過j的選法】

    10. 有依賴的背包問題

    有 N 個物品和一個容量是 V 的背包。物品之間具有依賴關系,且依賴關系組成一棵樹的形狀。如果選擇一個物品,則必須選擇它的父節點。如下圖所示:

    如果選擇物品5,則必須選擇物品1和2。這是因為2是5的父節點,1是2的父節點。每件物品的編號是 i,體積是 vi,價值是 wi,依賴的父節點編號是 pi。物品的下標范圍是 1…N。求解將哪些物品裝入背包,可使物品總體積不超過背包容量,且總價值最大。輸出最大價值。

    輸入格式

    第一行有兩個整數 N,V,用空格隔開,分別表示物品個數和背包容量。接下來有 N 行數據,每行數據表示一個物品。第 i 行有三個整數 vi,wi,pi,用空格隔開,分別表示物品的體積、價值和依賴的物品編號。如果 pi = ?1,表示根節點。 數據保證所有物品構成一棵樹。

    輸出格式

    輸出一個整數,表示最大價值。

    數據范圍

    1 ≤ N,V ≤ 100,1 ≤ vi,wi ≤ 100
    父節點編號范圍:內部結點:1 ≤ pi ≤ N;根節點 pi = ?1;

    輸入樣例

    5 7
    2 3 -1
    2 2 1
    3 5 1
    4 7 2
    3 6 2

    輸出樣例:

    11

    11. 背包問題求方案數

  • 問題描述:
  • 有 N 件物品和一個容量是 V 的背包。每件物品只能使用一次。第 i 件物品的體積是 vi,價值是 wi。求解將哪些物品裝入背包,可使這些物品的總體積不超過背包容量,且總價值最大。輸出最優選法的方案數。注意答案可能很大,請輸出答案模10 ^ 9 + 7的結果。

    輸入格式

    第一行兩個整數N,V,用空格隔開,分別表示物品數量和背包容積。接下來有 N 行,每行兩個整數 vi,wi,用空格隔開,分別表示第 i 件物品的體積和價值。

    輸出格式

    輸出一個整數,表示 方案數模10 ^ 9 + 7 的結果。

    數據范圍

    0 < N,V ≤ 1000
    0 < vi,wi ≤ 1000

    輸入樣例

    4 5
    1 2
    2 4
    3 4
    4 6

    輸出樣例:

    2

    734. 能量石

  • 問題描述:
  • 巖石怪物杜達生活在魔法森林中,他在午餐時收集了 N 塊能量石準備開吃。由于他的嘴很小,所以一次只能吃一塊能量石。能量石很硬,吃完需要花不少時間。吃完第 i 塊能量石需要花費的時間為 Si 秒。杜達靠吃能量石來獲取能量。不同的能量石包含的能量可能不同。此外,能量石會隨著時間流逝逐漸失去能量。第 i 塊能量石最初包含 Ei 單位的能量,并且每秒將失去 Li 單位的能量。當杜達開始吃一塊能量石時,他就會立即獲得該能量石所含的全部能量(無論實際吃完該石頭需要多少時間)。能量石中包含的能量最多降低至 0。請問杜達通過吃能量石可以獲得的最大能量是多少?

    輸入格式

    第一行包含整數 T,表示共有 T 組測試數據。每組數據第一行包含整數 N,表示能量石的數量。接下來 N 行,每行包含三個整數 Si,Ei,Li。

    輸出格式

    每組數據輸出一個結果,每個結果占一行。結果表示為 Case #x: y,其中 x 是組別編號(從 1 開始),y 是可以獲得的最大能量值。

    數據范圍

    1 ≤ T ≤ 10,
    1 ≤ N ≤ 100,
    1 ≤ Si ≤ 100,
    1 ≤ Ei ≤ 10 ^ 5,
    0 ≤ Li ≤ 10 ^ 5

    輸入樣例:

    3
    4
    20 10 1
    5 30 5
    100 30 1
    5 80 60
    3
    10 4 1000
    10 3 1000
    10 8 1000
    2
    12 300 50
    5 200 0

    輸出樣例:

    Case #1: 105
    Case #2: 8
    Case #3: 500
    樣例解釋

    在樣例#1中,有 N=4 個寶石。杜達可以選擇的一個吃石頭順序是:
    吃第四塊石頭。這需要 5 秒,并給他 80 單位的能量。
    吃第二塊石頭。這需要 5 秒,并給他 5 單位的能量(第二塊石頭開始時具有 30 單位能量,5 秒后失去了 25 單位的能量)。
    吃第三塊石頭。這需要 100 秒,并給他 20 單位的能量(第三塊石頭開始時具有 30 單位能量,10 秒后失去了 10 單位的能量)。
    吃第一塊石頭。這需要 20 秒,并給他 0 單位的能量(第一塊石頭以 10 單位能量開始,110 秒后已經失去了所有的能量)。
    他一共獲得了 105 單位的能量,這是能獲得的最大值,所以答案是 105。

    在樣本案例#2中,有 N=3 個寶石。
    無論杜達選擇吃哪塊石頭,剩下的兩個石頭的能量都會耗光。所以他應該吃第三塊石頭,給他提供 8 單位的能量。
    在樣本案例#3中,有 N=2 個寶石。杜達可以:
    吃第一塊石頭。這需要 12 秒,并給他 300 單位的能量。
    吃第二塊石頭。這需要 5 秒,并給他 200 單位的能量(第二塊石頭隨著時間的推移不會失去任何能量!)。
    所以答案是 500。

    【待更新】

    狀態機模型 ## 1049. 大盜阿福 ## 1057. 股票買賣 IV ## 1058. 股票買賣 V ## 1052. 設計密碼 ## 1053. 修復DNA狀態壓縮DP ## 1064. 小國王 ## 327. 玉米田 ## 292. 炮兵陣地 ## 524. 憤怒的小鳥 ## 529. 寶藏區間DP ## 1068. 環形石子合并 ## 320. 能量項鏈 ## 479. 加分二叉樹 ## 1069. 凸多邊形的劃分 ## 321. 棋盤分割樹形DP ## 1072. 樹的最長路徑 ## 1073. 樹的中心 ## 1075. 數字轉換 ## 1074. 二叉蘋果樹 ## 323. 戰略游戲 ## 1077. 皇宮看守數位DP ## 1081. 度的數量 ## 1082. 數字游戲 ## 1083. Windy數 ## 1084. 數字游戲 II ## 1085. 不要62 ## 1086.7不成妻單調隊列優化DP ## 135. 最大子序和 ## 1087. 修剪草坪 ## 1088. 旅行問題 ## 1089. 烽火傳遞 ## 1090. 綠色通道 ## 1091. 理想的正方形斜率優化DP ## 300. 任務安排1 ## 301. 任務安排2 ## 302. 任務安排3 ## 303. 運輸小貓第二章 搜索 包括Flood Fill、最短路模型、多源BFS、最小步數模型、雙端隊列廣搜、雙向廣搜、A*、DFS之連通性模型、DFS之搜索順序、DFS之剪枝與優化、迭代加深、雙向DFS、IDA*等內容Flood Fill ## 1097. 池塘計數 ## 1098. 城堡問題 ## 1106. 山峰和山谷最短路模型 ## 1076. 迷宮問題 ## 188. 武士風度的牛 ## 1100. 抓住那頭牛多源BFS ## 173. 矩陣距離最小步數模型 ## 1107. 魔板雙端隊列廣搜 ## 175. 電路維修雙向廣搜 ## 190. 字串變換A* ## 178. 第K短路 ## 179. 八數碼DFS之連通性模型 ## 1112. 迷宮 ## 1113. 紅與黑DFS之搜索順序 ## 1116. 馬走日 ## 1117. 單詞接龍 ## 1118. 分成互質組DFS之剪枝與優化 ## 165. 小貓爬山 ## 166. 數獨 ## 167. 木棒 ## 168. 生日蛋糕迭代加深 ## 170. 加成序列雙向DFS ## 171. 送禮物IDA* ## 180. 排書 ## 181. 回轉游戲第三章 圖論 包括單源最短路的建圖方式、單源最短路的綜合應用、單源最短路的擴展應用、Floyd算法、最小生成樹、最小生成樹的擴展應用、負環、差分約束、最近公共祖先、強連通分量、雙連通分量、二分圖、歐拉回路和歐拉路徑、拓撲排序等內容單源最短路的建圖方式 ## 1129. 熱浪 ## 1128. 信使 ## 1127. 香甜的黃油 ## 1126. 最小花費 ## 920. 最優乘車 ## 903. 昂貴的聘禮單源最短路的綜合應用 ## 1135. 新年好 ## 340. 通信線路 ## 342. 道路與航線 ## 341. 最優貿易單源最短路的擴展應用 ## 1137. 選擇最佳線路 ## 1131. 拯救大兵瑞恩 ## 1134. 最短路計數 ## 383. 觀光Floyd算法 ## 1125. 牛的旅行 ## 343. 排序 ## 344. 觀光之旅 ## 345. 牛站最小生成樹 ## 1140. 最短網絡 ## 1141. 局域網 ## 1142. 繁忙的都市 ## 1143. 聯絡員 ## 1144. 連接格點最小生成樹的擴展應用 ## 1146. 新的開始 ## 1145. 北極通訊網絡 ## 346. 走廊潑水節 ## 1148. 秘密的牛奶運輸負環 ## 904. 蟲洞 ## 361. 觀光奶牛 ## 1165. 單詞環差分約束 ## 1169. 糖果 ## 362. 區間 ## 1170. 排隊布局 ## 393. 雇傭收銀員最近公共祖先 ## 1172. 祖孫詢問 ## 1171. 距離 ## 356. 次小生成樹 ## 352. 闇の連鎖有向圖的強連通分量 ## 1174. 受歡迎的牛 ## 367. 學校網絡 ## 1175. 最大半連通子圖 ## 368. 銀河無向圖的雙連通分量 ## 395. 冗余路徑 ## 1183. 電力 ## 396. 礦場搭建二分圖 ## 257. 關押罪犯 ## 372. 棋盤覆蓋 ## 376. 機器任務 ## 378. 騎士放置 ## 379. 捉迷藏歐拉回路和歐拉路徑 ## 1123. 鏟雪車 ## 1184. 歐拉回路 ## 1124. 騎馬修柵欄 ## 1185. 單詞游戲拓撲排序 ## 1191. 家譜樹 ## 1192. 獎金 ## 164. 可達性統計 ## 456. 車站分級第四章 高級數據結構 包括并查集、樹狀數組、線段樹、可持久化數據結構、平衡樹、AC自動機等內容并查集 ## 1250. 格子游戲 ## 1252. 搭配購買 ## 237. 程序自動分析 ## 239. 奇偶游戲 ## 238. 銀河英雄傳說樹狀數組 ## 241. 樓蘭圖騰 ## 242. 一個簡單的整數問題 ## 243. 一個簡單的整數問題2 ## 244. 謎一樣的牛線段樹 ## 1275. 最大數 ## 245. 你能回答這些問題嗎 ## 246. 區間最大公約數 ## 243. 一個簡單的整數問題2 ## 247. 亞特蘭蒂斯 ## 1277. 維護序列可持久化數據結構 ## 256. 最大異或和 ## 255. 第K小數平衡樹 ## 253. 普通平衡樹 ## 265. 營業額統計AC自動機 ## 1282. 搜索關鍵詞 ## 1285. 單詞第五章 數學知識 包括篩質數、分解質因數、快速冪、約數個數、歐拉函數、同余、矩陣乘法、組合計數、高斯消元、容斥原理、概率與數學期望、博弈論等內容篩質數 ## 1292. 哥德巴赫猜想 ## 1293. 夏洛克和他的女朋友 ## 196. 質數距離分解質因數 ## 197. 階乘分解快速冪 ## 1289. 序列的第k個數 ## 1290. 越獄約數個數 ## 1291. 輕拍牛頭 ## 1294. 櫻花 ## 198. 反素數 ## 200. Hankson的趣味題歐拉函數 ## 201. 可見的點 ## 220. 最大公約數同余 ## 203. 同余方程 ## 222. 青蛙的約會 ## 202. 最幸運的數字 ## 1298. 曹沖養豬矩陣乘法 ## 1303. 斐波那契前 n 項和 ## 1304. 佳佳的斐波那契 ## 1305. GT考試組合計數 ## 1307. 牡牛和牝牛 ## 1308. 方程的解 ## 1309. 車的放置 ## 1310. 數三角形 ## 1312. 序列統計 ## 1315. 網格 ## 1316. 有趣的數列高斯消元 ## 207. 球形空間產生器 ## 208. 開關問題容斥原理 ## 214. Devu和鮮花 ## 215. 破譯密碼概率與數學期望 ## 217. 綠豆蛙的歸宿 ## 218. 撲克牌博弈論 ## 1319. 移棋子游戲 ## 1321. 取石子 ## 1322. 取石子游戲第六章 基礎算法 包括位運算、遞推與遞歸、前綴和與差分、二分、排序、RMQ等內容位運算 ## 90. 64位整數乘法遞推與遞歸 ## 95. 費解的開關 ## 97. 約數之和 ## 98. 分形之城前綴和與差分 ## 99. 激光炸彈 ## 100. 增減序列二分 ## 102. 最佳牛圍欄 ## 113. 特殊排序排序 ## 105. 七夕祭 ## 106. 動態中位數 ## 107. 超快速排序RMQ ## 1273. 天才的記憶

    總結

    以上是生活随笔為你收集整理的AcWing-算法提高课【合集】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。