背包問題【DP】
- 有一個背包,背包容量是M=150kg。有7個物品,物品不可以分割成任意大小。要求盡可能讓裝入背包中的物品總價值最大,但不能超過總容量。
01背包
f[j]=max(f[j],f[j-w[i]]+c[i]);
搬書【DP】
- 陳老師桌上的書有三堆,每一堆都有厚厚的一疊,你想逗一下陳老師,於是你設計一個最累的方式給他,讓他把書拿下來給同學們。若告訴你這三堆分別有i,j,k本書,以及每堆從下到上書的質量,每次取書只能從任一堆的最上面取,顯然,每次取書陳老師的體力消耗都會加大,這里用體力系數代表,取下第一本書時,體力系數為1,第二本書時體力系數為2,依次類推,而每次體力消耗值則為體力系數與書的重量之積。
n^3枚舉從哪一堆上選
f[a][b][c] = max(f[a-1][b][c]+w[1][a]*T,f[a][b-1][c]+w[2][b]*T,f[a][b][c-1]+w[3][c]*T);
排隊問題(貪心策略明顯)【反證法】
- 在一個醫院B超室,有n個人要做不同身體部位的B超,已知每個人需要處理的時間為t[i](1≤i≤n),請求出一種排列次序,使每個人排隊等候時間總和最小。
按時間從小到大排。
證明:若t[i]>t[j],交換i,j一定能得到更優的解
神牛果(貪心策略明顯)【反證法】
- 在某次膜拜大會上,n個神牛被要求集體膜拜。這些神牛被獎勵每人吃一些神牛果。但是,每個神牛的肚量不一樣。為了不顯得某些人吃得太多,決定兩人一組,使得吃得最多的那組吃得盡量少。
排序,每次取出最大和最小的為一組。
修理牛棚(貪心策略明顯)【倒推法】
- John的牛棚一個緊挨着另一個排成一行,有些牛棚里有牛,有些沒有,所有的牛棚有相同的寬度。 自門遺失以后,農民John必須盡快在牛棚前面豎立起新的木板。 他的新木材供應商將會供應他任何他想要的長度,但是供應商只能提供有限數目的木板。農民John想將他購買的木板總長度減到最少。
- 給出能買到的木板最大的數目M,牛棚的總數S(1≤S≤200),牛棚里牛的總數C(1≤C≤S),和牛所在的牛棚的編號X(1≤X≤S)。輸出所需木板的最小總長度作為答案。
初始為一整塊木板,可以選擇m-1個斷點。
將斷開的長度從大到小排。
刪數(貪心策略明顯)【倒推法】
- 給定n(n≤100)位正整數a,去掉其中任意k≤n個數字后,剩下的數字按原次序排列組成一個新的正整數。對於給定的n位正整數a和正整數k,設計一個算法找出剩下數字組成的新數最小的刪數方案。
因為一共選n-k個數,設當前為第i個,上次選了第L個
至少要留n-k-i個給后面,那么第i個即為min(a[L+1]~a[n-k-i+1])
(或者:從高位到低位遍歷k次,如果數字遞增則刪最大的(最后一位);
否則刪開始遞減的第一個(左邊第一個遞減區間的第一位),比如123654798,就刪掉6 )
調整法:列出不等式,交換等式兩邊得到貪心方案
奶酪工廠(貪心策略不明顯)【調整法】
- 接下來的N(1≤N≤10000)星期中,奶酪工廠在第i個星期要花C_i分來生產一個單位的奶酪。約克奶酪工廠擁有一個無限大的倉庫,每個星期生產的多余的奶酪都會放在這里。而且每個星期存放一個單位的奶酪要花費S分。
- 工廠最近收到了客戶N個星期的訂單,第i個星期要向客戶提供Y_i 個單位的奶酪。當然這些奶酪可以在第i個星期時生產,也可以從倉庫中拿取。采用怎樣的生產策略約克奶酪工廠的花費最小呢?
某周需要的奶酪一定在同一周生產,也就是說與奶酪訂單需要量無關。
問題可以轉化為當前周生產奶酪的最低價格。
設i<j<k,如果c[i]+(j-i)*s < c[j],則:
c[i]+(j-i)*s+(k-j)*s < c[j]+(k-j)*s
c[i]+(k-i)*s < c[j]+(k-j)*s
設第i周的最優生產時間為f[i],則一定有f[i] = f[i-1]或i
每次比較並記錄當前周的生產時間即可。
堆積木【調整法】
- 現在有N塊積木,每塊積木都有自重W和正常狀態下的承重能力F,現在要把這N塊積木壘在一起,但是有可能某塊積木的負重超過了它在正常狀態下的承重能力,那么這塊積木就有被壓壞的危險,請問應該如何堆這N塊積木使得N塊積木中最大的壓力指數最小。這里定義壓力指數為該積木的負重與其在正常狀態下的承重能力的差值。
- 1≤N≤50000,1≤W≤10000,1≤F≤10^9。
沒想出來
設當前最優的方案從下到上積木編號為1,2
則有f[1]-w[2] < f[2]-w[1]
f[1]+w[1] < f[2]+w[2]
即從下到上的順序是按f+w從小到大排。
國王游戲【調整法】
- 國王邀請n位大臣來玩一個有獎游戲。首先,他讓每個大臣在左、右手上面分別寫下一個整數,國王自己也在左、右手上各寫一個整數。然后,讓這n位大臣排成一排,國王始終站在隊伍的最前面。排好隊后,所有的大臣都會獲得國王獎賞的若干金幣,每位大臣獲得的金幣數分別是:排在該大臣前面的所有人的左手上的數的乘積除以他自己右手上的數,然后向下取整得到的結果。
- 國王想請你幫他重新安排一下隊伍的順序,使得獲得獎賞最多的大臣,所獲獎賞盡可能的少。
設當前最優的方案從前到后編號為0,1,2(0為國王)
則max(a[0]/b[1],a[0]*a[1]/b[2]) < max(a[0]/b[2],a[0]*a[2]/b[1])
因為一定有a[0]*a[2]/b[1] > a[0]/b[1],a[0]*a[1]/b[2] > a[0]/b[2]
所以轉化為 a[0]*a[1]/b[2] < a[0]*a[2]/b[1]
a[1]*b[1] < a[2]*b[2]
即按從前往后的順序是按a*b從小到大排。
讓步法:競爭公共資源時,盡量使剩余選擇最大化 我瞎編的
智力大沖浪【讓步法】
- 比賽時間分為n(n≤5000)個時段,給出了很多小游戲,每個小游戲都必須在規定期限ti(1≤ti≤n)。如果一個游戲沒能在規定期限前完成,則要從獎勵費m元中扣去一部分錢wi,wi為自然數,不同的游戲扣去的錢是不一樣的。當然每個游戲本身都很簡單,保證每個參賽者都能在一個時間段內完成,而且必須從整時段開始。主持人只是想考考每個參賽者如何安排組織自己做游戲的順序。作為參賽者,小偉很想贏得冠軍,當然更想贏取最多的錢!
總錢數是一定的,問題轉化為使扣去的錢最少。
按w從大到小排序。
檢查1~t[i]是否有時間沒有沒占用,如果都被占了則要扣去w[i]的錢
如果有可選的,則盡量選擇時間靠后的,給其他的留出前面的時間!
整數區間【讓步法】
- 我們定義一個整數區間[a,b]:是一個從a開始至b 結束的連續整數的集合。編一個程序,對給定的 n(n≤1000 )個區間,找出滿足下述條件的所含元素個數最少的集合中元素的個數:對於所給定的每一個區間,都至少有兩個不同的整數屬於該集合。
按右端點從小到大排序。這樣右端點單調,即保證,在當前選取的整數序列a[]中,
若下一個區間不包含a[i],則一定不包含a[i-1],a[i-2]….
即最有可能被下一個區間包含的一定是最右邊的數。
設當前已經選取的整數中,最右邊的兩個數為x,y。
檢查x,y是否被當前區間包含;若都包含,則繼續下一個區間;
若不包含x,包含y,則選擇這個區間的右端點。
若都不包含,則選擇最右的兩個(右端點-1和右端點)。
這樣選擇出來的數是單調遞增的,且盡量大,也就是被下一個區間包含的機會盡量大。
活動選擇【讓步法】
- 假設有一個需要使用某一資源的n(n≤1000 )個活動組成的集合S,S={1,…,n}。該資源一次只能被一個活動占有,每一個活動有一個開始時間b[i]和結束時間e[i](b[i]≤e[i])。若b[i]>e[j]或者b[j]>e[i],則活動 i 和活動 j 兼容。
- 你的任務是:選擇由互相兼容的活動組成的最大集合。
上一個活動結束的越早越好。
按右端點從小到大排序,能選則選。
雷達安裝【讓步法】
- 假定海岸線是一條無限延伸的直線,陸地在海岸線的一邊,大海在另一側。海中有許多島嶼,每一個小島我們可以認為是一個點。現在要在海岸線上安裝雷達,雷達的覆蓋范圍是d,也就是說大海中一個小島能被安裝的雷達覆蓋,那么它們之間的距離最大為d。
- 我們使用平面直角坐標系,定義海岸線是x軸,大海在x軸上方,陸地在下方。給你海中每一個島嶼的坐標位置(x,y)和要安裝的雷達所覆蓋的范圍d,你的任務是寫一個程序計算出至少安裝多少個雷達能將所有的島嶼覆蓋。
雷達的覆蓋范圍是一樣的,
每個小島可以被一定范圍內的雷達覆蓋到,可求出每個小島可選的雷達區間。
轉化為和整數區間類似的問題。
按右端點排序,設安裝的雷達中最右的橫坐標為x。
若x在這個小島的區間內,則繼續;否則選這個小島的區間的右端點安裝雷達。
曬衣服(貪心+桶)
- 假設衣服在自然條件下用1的單位時間可以曬干A點濕度。摳門的Smart買了1台烘衣機。使用烘衣機可以讓他用1個單位時間使1件衣服除了自然曬干的A點濕度外,還可烘干B點濕度,但在1個單位時間內只能對1件衣服使用。
- N件的衣服因為種種原因而不一樣濕,現在告訴你每件衣服的濕度,要你求出弄干所有衣服的最少時間(濕度為0為干)。
因為每個單位時間所有衣服自然曬干1點,所以要使每個單位時間濕度最大的衣服濕度最小
所以烘干機給當前濕度最大的用就行了。
維護一個優先隊列,元素為初始濕度,每次取出隊首,把它減去B點濕度,再壓回去。
當隊首小於A*t時,說明已全部晾干
游戲通關(貪心+並查集)
- 小明需要完成N個任務才能將這個游戲通關。
- 每個任務完成時限T,就是這個任務必須在時間T之前完成(你可以認為游戲剛開始的時間為1),還有完成這個任務小明可以獲得一定的獎勵W。由於小明嫻熟的技術以及任務的簡單,他可以在一個單位時間將任務完成。
- 小明想要在老師到來之前將任務全部完成,同時他也想獲得最多的獎勵。
- N≤200000,Ti≤200000,Wi≤2000
這道題和智力大沖浪相同,只是將最小減少獎勵改為最大增加獎勵;
獎勵從大到小排序,並且在可行區間內盡量往后放。
不過數據范圍較大,如果暴力枚舉1~t[i]大概會超時。
用並查集優化:把已占用的時間全部連起來,fa[x]-1即為可選的;
想要選擇時間x時,若x可用,分別判斷x-1、x+1是否也已被占用,被占用則與x連接;
若x不可用,則上一個可用的時間即為getfa(x)-1。
探險(貪心+堆)
- 一群驢友駕駛一輛卡車前往樹林里探險。但是由於他們的駕駛技術太糟,油箱在路上給弄破了,所以他們每前進一個單位的路程就會消耗掉一個單位的油(包括漏掉的汽油),為了修好油箱,驢友們必須前往最近的城市。在當前位置和城市之間有N個加油站,驢友們可以在加油站加1到100單位的油(每個加油站存油量不等)。對於人來說,樹林是個危險的地方。所以,驢友們要盡可能的少停站加油。幸運的是,這輛卡車的油箱非常大,你可以認為它的容量是無窮大的。卡車在離城P個單位時還有L個單位的油。 你要算出驢友們至少要停幾站才能到城市,或者驢友們根本到不了城市。
油不花錢,油箱也沒有容量上限,從起點到終點需要的油是一定的。
想要加油次數盡量少,就要每次加的油盡量多。按存油量大小維護優先隊列。
在起點到終點的路上,一定會經歷每一個加油站。
枚舉每一個加油站,如果當前的總油量能到達,則可以在這里加油,把它加入優先隊列。
如果不能到達,則在能加油的加油站中加最多的,即取出優先隊列的隊首,加入總油量,直到總油量能到達這個加油站為止。
若優先隊列為空時也到不了則無解。
優惠券(貪心+堆)【調整法】
- 新學期開學了,Smart准備買一些新書,書店有N本新書,第i本新書價格為Pi,使用優惠券購買第i本書時價格會降為Ci。Smart有K張優惠券,每本新書只能使用一次優惠券。Smart想知道花不超過M的錢最多可以買多少本新書?
要買的最多,那一定是先買優惠券價最便宜的。
如果優惠券沒用完,錢就花光了,當前買的書即為答案。
如果錢還有剩,那么對於剩下的n-k本書,
判斷是用原價買它,或把另一本書的優惠券給它而另一本原件買比較便宜。
但是若枚舉所有已經使用優惠券的書,時間復雜度顯然不友好。
交換條件為c[j]+p[i] < c[i]+p[j],即p[i]-c[i] < p[j]-c[j]
因此,優先隊列要維護的是:原價和優惠券價的差值,從小到大排。
每當對某本書使用優惠券時,把它的差值壓入優先隊列。
探討人生(貪心+枚舉)
- Smart每次他與好友A探討人生要花費a個小時,並可以得到x點人生經驗;每次與好友B探討人生要花費b個小時,並得到y點人生經驗。但是Smart的精力是有限的,他只能抽出n個小時來跟他的友人們探討人生,若這n個小時並沒有被用完,則Smart會把剩下的時間拿來跟好友C聊天,而這並不能得到人生經驗。現在Smart想知道,他最多可以得到多少點人生經驗。
- n≤1e12(我隨便寫的)
這不是多重背包嗎
貪心優化暴力…
因為只有兩個人,所以暴力枚舉探討次數就可以了。
原來沒給數據范圍,所以我編了一個… √n可過。
剪枝:先swap一下,保證與A探討單位時間經驗更多。
為了使枚舉的探討次數控制在√n以內,需要判斷一下:
若a>√n,則枚舉次數一定小於√n,正常枚舉與a探討次數即可。
否則,枚舉與B探討次數。
因為與A探討更優,即與A探討b次優於與B探討a次,
所以當枚舉與B探討次數大於等於a時,一定不如把其中的a次變成和A探討。
所以最多只要枚舉a次。
數字游戲(貪心+DP)
- 小W發明了一個游戲,他在黑板上寫出一行數字a1,a2,…an(n≤200),然后給你m個回合的機會,每個回合你可以從中選一個數擦除它,接着剩下來的每個數字ai都要遞減一個值bi。如此重復m個回合,所有你擦除的數字之和就是你得到的分數。
- 編程幫小W算算,對於每個給出的an和bn序列,可以得到的最大得分是多少?
貪心得到dp枚舉順序。
當m=n,即全選時,顯然按b從大到小選。
m<n時,需要用dp解決,但策略是相同的,即把b從大到小排序。
設f[j]表示選j個數得到的最大價值。
狀態轉移方程:f[j] = max(f[j-1]+a[i]-b[i]*(j-1))
馬步距離(貪心+搜索)
- 在國際象棋和中國象棋中,馬的移動規則相同,都是走“日”字,我們將這種移動方式稱為馬步移動。如圖所示。
- 從標號為 0 的點出發,可以經過一步馬步移動達到標號為 1 的點,經過兩步馬步移動達到標號為 2 的點。任給平面上的兩點 p 和 s ,它們的坐標分別為 (xp,yp) 和 (xs,ys) ,其中,xp,yp,xs,ys 均為整數。假設棋盤充分大,並且坐標可以為負數。現在請你求出從點 p 到點 s 至少需要經過多少次馬步移動?
- xp,yp,xs,ys < 10000000。
直接搜索會超時,考慮優化。
因為棋盤無限大,所以四個方向是一樣的,也就是說可以任意進行對稱。
為了方便,把s翻轉到p的右下。
通過打表可以發現, p和s相距較遠時,移動的方式只有從(x,y)到(x+1,y+2)或(x+2,y+1),
也就是一直向右下走就行了…
打出大概5,5的矩陣(不放心的話就多打點…),當距離差超出這個矩陣時,
取絕對值,令x,y>0,swap使x>y,將x-=2,y-=1。
當x,y進入矩陣時,直接返回答案即可。
不想打表的話,也可以把x,y縮小到一定范圍內后進行bfs。