主頁 > 軟體設計 > XDOJ(智慧平臺)--分配寶藏(用動態規劃dp演算法解決)(C語言)

XDOJ(智慧平臺)--分配寶藏(用動態規劃dp演算法解決)(C語言)

2020-12-31 13:16:17 軟體設計

------------------------------------------------------------
作為西電渣渣,這是我第一次接觸需要一些很明確的演算法的題目,

第一次博客寫廢話較多hhh,可以直接到下面看分析

我在昨天晚上和舍友一起肝這道題,肝了一個晚上都沒有解決,甚至沒有一個很明確的思路,以至于躺在床上都想著怎么寫這道題 (畢竟智慧平臺上都會出現的題目,難道期末考試不會考嗎) 于是來社區看看有沒有西電學長 (其實更希望是學姐) 這里推一推學長的博客 XDU-分配寶藏,

但是本人看著稍微有點復雜的代碼就頭疼,于是去b站找了dp演算法的視頻動態規劃DP0-1背包,看了一半恍然大悟(假的)寫出來一個遞回函式交上去,發現一半的例子都超時了(淚目),看完視頻才知道dp演算法是怎么樣寫的,
在這里插入圖片描述
然后就這樣心血來潮,寫下這篇博客,
本文章(大概、或許、可能)算是視頻和學長博客的結合吧,
------------------------------------------------------------

內容

一. Dynamic Programming (DP演算法)
二. 舉例(斐波那契數列,0-1背包)
三. 分配寶藏

------------------------------------------------------------

一、Dynamic Programming (DP演算法)

DP,聽起來挺高級的一個東西,我第一次接觸是在洛谷上,但是當時感覺學這玩意還早,就忽視了它,直到我在XDOJ上遇到了它,就有了這篇博客…
DP,中文名譯為動態規劃,是求解決策程序最優化的程序,各個階段采取的決策,一般來說是與時間有關的,決策依賴于當前狀態,又隨即引起狀態的轉移,一個決策序列就是在 變化的狀態中 產生出來的,故有“動態”的含義,(參考 百度百科—動態規劃)
下面將直接用例子來說明dp演算法,

二、舉例(斐波那契數列,0-1背包)

例1. 斐波那契數列

眾所周知,斐波那契數列是這樣的:
F(0)=1
F(1)=1
F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
實際上,這個公式就是一個遞回的思路,從我們需要求的那個值逐個歸回到F(0)和F(1)
由這個公式我們可以寫出一個遞回函式,其中遞回結束的標志是n=0或n=1.

int F(int n){
	int res;
	if(n<2) res=1;
	else res=F(n-1)+F(n-2);
	return res;
}
//再簡化一下可以寫成這樣
int F(int n){
	return n<2?1:F(n-1)+F(n-2);
}

又眾所周知,函式呼叫需要額外的空間(堆疊)來完成,在呼叫次數很多的情況下會降低程式效率,并且遞回呼叫可能會導致大量的重復計算,所以我們需要把這個遞回函式改造成一個效率更高的形式,
可以看到,遞回是從我們要的F(n)一直計算到F(0)和F(1),然后再回傳到F(n),在這個程序中,程式在不斷地分配空間,降低效率,那我們該怎么改才能提高效率呢?

舉個栗子,在Minecraft中,有一處懸崖,附近有一扇門,而門的鑰匙落在了懸崖底部,Steve需要取鑰匙開門,他有兩種方法,一個是遞回,一個是dp

遞回意味著他從懸崖下去,但他不知道懸崖的高度,因此需要不斷地造梯子,爬下來,再回傳,來完成這個任務,

dp,真是個好東西,它將Steve傳送到了懸崖的底部,并且告訴他懸崖的高度,這個時候,Steve只需要造一定數量的梯子直接搭上去完成任務,(咳咳,這個例子可能有點離譜,但是無傷大雅,dddd)

按照這個想法,遞回就相當于從高層走向底層,再回傳高層;dp就是從底層打基礎到高層,效率更高,
那如何打基礎呢?(再回到斐波那契數列)
我們知道當n>2的時候,F(n)=F(n-1)+F(n-2),一直到F(0)和F(1),而F(0)和F(1)就是最基礎的基礎,(這個時候有小伙伴就要說了,遞回函式不也有這個基礎嗎?答:不要在意這些細節~)dp就是要從基礎入手,又又眾所周知,要求F(n),就要把F(n-1)到F(0)全部求一遍,那就求呀,由此我們可以寫出這么一段代碼:

int F[10000];					//陣列多大無所謂,只要夠用就行
F[0]=F[1]=1;					//初始化F[0]和F[1]
for(int i=2;i<=n;i++)        	//從F[2]開始到F[n]
	F[i]=F[i-1]+F[i-2];			//套公式

//改寫成函式
int Fib(int n){
	int F[10000]={1,1};
	for(int i=2;i<=n;i++)
		F[i]=F[i-1]+F[i-2];
	return F[n];
}

然后,dp這個方法就寫完了,然后可能有的小伙伴就懵了,直呼就這?
沒錯,就這,我們要的F[n]就出來了,
(這時候我突然想起,在剛學遞回的時候,其實就接觸到了這樣簡單的dp)
實際上dp演算法就像學長@西電蔡徐坤所說的記憶化搜索一樣,取之前已經計算過的值,效率更高,
這時候就有小伙伴說了,那遞回豈不是一無是處,當然不是了,在很多演算法中,有遞回做得到而dp做不到的地方,以后或許能夠接觸到

例2. 0-1背包問題

做完一維的,這個時候再來個二維豈不妙哉~
在這里插入圖片描述
如圖所示,這就是一個經典的0-1背包問題,
我們設V為背包價值,k為能偷的物品數量,w為背包容量,wi 為第 i 件物品的重量,vi 為第i件物品的價值,則有V=V( k , w ),
在這題中,我們要求的就是V( 4 , 8 ),我們選擇從第k件(也就是第四件)開始偷,然后是k-1,k-2 … 2,1件,

從第4件物品開始,我們可以選擇偷和不偷,
①.如果選擇偷,那么V( 4 , 8 )=V( 4 - 1 , 8 - w4 ) + v4=V( 3 , 3 ) + 8
②.如果選擇不偷,則V( 4 , 8 )=V( 4 - 1 , 8 )=V( 3 , 8 )

取①的結果V( 3 , 3 ) + 8
③.發現這個時候的 w(背包容量)< w3,因此只能選擇不偷,所以V( 3 , 3 ) + 8=V( 2 , 3 ) + 8
取②的結果V( 3 , 8 )
④.選擇偷,那么V( 3 , 8 )=V( 3 - 1 , 8 - w3 ) + v3=V( 2 , 4 ) + 5
⑤.選擇不偷,則V( 3 , 8 )=V( 3 - 1 , 8 )=V( 2 , 8 )

??????
這樣推下去,我們可以得到這樣的一個簡單公式
在這里插入圖片描述
而我們要求的應該是最大值,再加上背包容量不夠的情況,得到狀態轉移方程

在這里插入圖片描述
看到這里各位小伙伴是不是就可以寫一個遞回函式出來了,這里我就不再寫了(懶),
那這個遞回結束的標志應該是什么呢?
不難想到,當能偷的物品數量為0或者背包剩余容量為0時,遞回就該結束了,
因此V( k , 0 )=V( 0 , w )≡0
可以得到這么一個表格
在這里插入圖片描述
由此按照例1的思想,是不是就直接能寫出代碼呢?
這里給出代碼片段,剩下的交給小伙伴們自己寫出來,

int v[5][9]={0};					
int w[]={0,2,3,4,5};
int v[]={0,3,4,5,8};
for(int k = 1; k <= 4; k++)						//k表示第k件物品
	for(int W = 1;W <= 8; W++){					//W表示背包剩余容量為W
		if(w[i]>W)								//物品重量大于背包剩余容量,不偷
			v[k][W]=v[k-1][W];
		else									//否則,從偷和不偷中選出最大值
			v[k][W]=max( v[k-1][W] ,v[k-1][W-w[k]]+v[k] );//max函式自己寫,或者用a?b:c運算式
	}											//v[4][8]就是要的答案

三、分配寶藏

事件的導火索可不能忘了

標題
分配寶藏
類別
綜合
時間限制
2s
記憶體限制
256Kb
問題描述
兩個尋寶者找到一個寶藏,里面包含n件物品,每件物品的價值分別是W[0],W[1],…W[n-1],
SumA代表尋寶者A所獲物品價值總和,SumB代表尋寶者B所獲物品價值總和,請問怎么分配才能使得兩人所獲物品價值總和差距最小,即兩人所獲物品價值總和之差的絕對值|SumA - SumB|最小,

輸入說明
輸入資料由兩行構成:
第一行為一個正整數n,表示物品個數,其中0<n<=200,
第二行有n個正整數,分別代表每件物品的價值W[i],其中0<W[i]<=200,

輸出說明
對于每組資料,輸出一個整數|SumA-SumB|,表示兩人所獲物品價值總和之差的最小值,

輸入樣例
4
1 2 3 4

輸出樣例
0

題目分析
這道題和例題2很像,但唯一不同的就是,物品的重量相當于價值,
題目要求A與B之差的絕對值最小,而物品總價值時固定的,因此將背包容量設為sum/2,

下面直接給出我的代碼(盡量用代碼里的注釋解釋代碼)

#include<stdio.h>
int W[201], sum, dp[201][20001];	//[201]是便于將物品從1開始編號
									//[20001]同理
int max(int a,int b);
int main(void)
{
	int n, i, j, sumA;				//假設A得到的永遠是較少的那個
	scanf( "%d", &n);
	for(i = 1; i <= n; i++){	i代指第i個物品
		scanf( "%d", &W[i] );
		sum += W[i];
	}
	for(i = 1; i <= n; i++){
		if (W[i] > sum/2){			//如果物品某個價值大于總價值的一半,其余物品將給A,不需要再計算
			dp[n][sum/2] =sum-W[i];
			break;
		}
		for(j = 1; j <= sum/2; j++){//j分別代指第i個物品和背包剩余容量
			if(W[i] > j) 			//同樣的,物品重量大于背包剩余容量,不偷
				dp[i][j] = dp[i-1][j];
			else 
				dp[i][j] = max( dp[i-1][j] , dp[i-1][j-W[i]] + W[i]);
		}
	}
	sumA = dp[n][sum/2];//個人比較喜歡單一出口
	printf("%d\n", sum - 2 * sumA);//因為A總是得到較少的那個,不需要再加上絕對值
	return 0;
}
int max(int a,int b){
	int m = a;
	if( a < b) m = b;
	return m;
}

這樣,這篇博客就到此結束了,希望對小伙伴們有一定幫助,同時也歡迎小伙伴們提出自己的想法和建議,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/242955.html

標籤:其他

上一篇:C++繼承中的賦值兼容規則你了解多少???

下一篇:[溝通能力] 述職,你搞定了嗎?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more