1. 程式人生 > >演算法入門系列二--DP入門之DAG上的DP

演算法入門系列二--DP入門之DAG上的DP

/***** DP初步之DAG ********/

/******** written by C_Shit_Hu ************/

////////////////動態規劃入門///////////////

/****************************************************************************/
/* 
第一個DAG模型:矩形巢狀問題
描述
有n個矩形,每個矩形可以用a,b來描述,表示長和寬。
矩形X(a,b)可以巢狀在矩形Y(c,d)中當且僅當a<c,b<d或者b<c,a<d(相當於旋轉X90度)。
例如(1,5)可以巢狀在(6,2)內,但不能巢狀在(3,4)中。
你的任務是選出儘可能多的矩形排成一行,使得除最後一個外,每一個矩形都可以巢狀在下一個矩形內。

輸入
測試資料的第一行是一個正正數n,表示該組測試資料中含有矩形的個數(n<=1000)
隨後的n行,每行有兩個數a,b(0<a,b<100),表示矩形的長和寬

輸出
每組測試資料都輸出一個數,表示最多符合條件的矩形數目,每組輸出佔一行
*/
/****************************************************************************/


// 思路:先對長和寬來此排序,再按照要求構圖,
// 完成之後,直接記憶化搜尋,值得注意的地方是你不能只從第一個點搜尋,而是要從每個點搜尋

#include<stdio.h>
#include<string.h>

#define MAXN 101
int n, G[MAXN][MAXN];     // 圖的儲存
int x[MAXN], y[MAXN], d[MAXN];  // 節點

//記憶化搜尋來完成的動態轉移
int dp(int i) 
{       
	int j;
	if(d[i] > 0) 
		return d[i];  // 如果已經計算過,直接返回其值

	d[i] = 1;         // 否則,置一,遞推計算
	for(j = 1; j <= n; j++)
		if(G[i][j])   // 如果圖存在,即是滿足可巢狀
			if(d[i] <=dp(j)+1)     // 如果存在可巢狀的節點d(j)加一後其值大於d(i)
				d[i]=dp(j)+1;      // 則使d[i]更新

			return d[i];       // 返回d[i]
}

//按字典序只輸出排序最小的序列
/*
此部分的原理:字典序只是消除並列名次的方法,我們最根本的任務還是求出最長路
在把所有的d值計算出來後,選擇最大的d[i]所對應的i。而如果有多個i,則選擇最小的i,這樣保證字典序最小。
接下來選擇d(i) = d(j) +1 且i, j ∈E 的任何一個j,但是為滿足字典序最小,需選擇最小的j
*/
void print_ans(int i) 
{   
	int j;
	printf("%d ", i);    // 第一次i代表最長路的起點節點,以後均代表從該節點開始的路徑
	for(j = 1; j <= n; j++) 
		if(G[i][j] && d[i] == d[j]+1)  // 如果該圖滿足可巢狀,且d[i] = d[j] +1
		{
			print_ans(j);           // 立即輸出從節點j開始的路徑
			break;
		}
}

int main() 
{
	int i, j, t, ans, best;
	scanf("%d", &n);            // n表示矩形的數目
	// 初始化矩形長寬引數,並初次調整長寬順序
	for(i = 1; i <= n; i++) 
	{
		scanf("%d%d", &x[i], &y[i]);     // 依次輸入矩形的邊長資訊
		if(x[i] > y[i]) 
		{
			t = x[i]; x[i] = y[i]; y[i] = t;   // 保證X[]存的是長,Y[]存的是寬
		}
	}
	memset(G, 0, sizeof(G));  // 陣列清零
	for(i = 1; i <= n; i++)           // 建圖
		for(j = 1; j <= n; j++)
			if(x[i] < x[j] && y[i] < y[j]) G[i][j] = 1;  // 如果第i個矩形的長寬均小於第j個,使圖相應的值為1
			
			ans = 0;
			for(i = 1; i <= n; i++)      // 依次遞推所有的的節點
				if(dp(i) > ans) 
				{
					best = i;       // best 是最小字典序
					ans = dp(i);
				}
				printf("ans=%d\n", ans);   // 表示最長路長度
				print_ans(best);
				printf("\n");
				while(1);
			return 0 ;
}

/******************************************************/
/********************  心得體會  **********************/
/*
好好學習DP!!!
*/
/******************************************************/

執行結果如下:

相關推薦

ActiveMQ入門系列入門程式碼例項(點對點模式)

在上一篇《ActiveMQ入門系列一:認識並安裝ActiveMQ(Windows下)》中,大致介紹了ActiveMQ和一些概念,並下載、安裝、啟動他,還訪問了他的控制檯頁面。 這篇,就用程式碼例項說下如何實現訊息的生產和消費。 一、理論基礎 同RabbitMQ一樣,ActiveMQ中也是有兩種模式:

演算法入門系列--DP入門DAGDP

/***** DP初步之DAG ********/ /******** written by C_Shit_Hu ************/ ////////////////動態規劃入門/////////////// /*****************************************

C語言入門十)列舉

C語言中,列舉就是專門用於表示幾種固定型別的取值。列舉的本質就是基本資料型別, 就是整形。 列舉和結構體一樣, 要想定義列舉型別變數, 那麼必須先定義列舉型別。 列舉型別定義的格式   enum 列舉型別名稱 { 取值, }; // 1.

安卓入門系列-05常見佈局RelaiveLayout(相對佈局)

接著上一篇提到的線性佈局,如果說線性佈局是遵循一種順序排放,一處存在一個元件就不會存在另一個。那麼相對佈局則是位置上的相對關係(對於其他元件),不指定相對位置則會堆在一起重疊起來。 1.什麼是相對佈局 相對佈局指的是有參照的佈局方式,就是以某個兄弟元件,或者父容器來決定元

經典演算法研究系列 續 徹底理解Dijkstra演算法

                       經典演算法研究系列:二之續、徹底理解Dijkstra演算法 作者:July   二零一一年二月十三日。參考程式碼:introduction to algorithms,Second Edition。---------------------------------

Metasploit入門系列()——初識模組

十分抱歉,我居然沒有在第一期粘出MSF的官方連結: https://www.metasploit.com/ 在這裡你可以獲得官方文件及其他幫助 官方文件中有大量API開發規範 這help是不是同感個性滿分呢~ now !302強行跳轉!開課 ! 上圖是對MSF架構

Android入門教程十九ProgressBar(進度條)

本節引言: 本節給大家帶來的是Android基本UI控制元件中的ProgressBar(進度條),ProgressBar的應用場景很多,比如 使用者登入時,後臺在發請求,以及等待伺服器返回資訊,這個時候會用到進度條;或者當在進行一些比較 耗時的操作,需要等待一段

MongoDB入門系列() ===> 建立使用者

本文程式碼測試環境: win10, MongoDB 4.0.5 剛安裝好的mongodb會提示: 2019-01-05T11:22:42.470+0800 I CONTROL [initandlisten] ** WARNING: Access control is not e

Gradle入門系列()——groovy高階語法

groovy高階語法 一、json操作 使用groovy自帶的json工具進行json操作 groovy.json.JsonSlurper:將json原資料轉成實體物件 groovy.json.JsonOutput:將實體物件轉成json資料 def list = [ new Perso

SSE影象演算法優化系列十六:和時間賽跑優化高斯金字塔建立的計算過程。

  影象金字塔技術在很多層面上都有著廣泛的應用,很多開源的工具也都有對他們的建立寫了專門的函式,比如IPP,比如OpenCV等等,這方面的理論文章特別多,我不需要贅述,但是我發現大部多分開源的程式碼的實現都不是嚴格意義上的金字塔,而是做了一定的變通,這種變通常常為了快捷的實現類似的效果,雖然這種變通不太會影響

spring cloud 入門系列:使用Eureka 進行服務治理

服務治理可以說是微服務架構中最為核心和基礎的模組,它主要用來實現各個微服務例項的自動化註冊和發現。 Spring Cloud Eureka是Spring Cloud Netflix 微服務套件的一部分,主要負責完成微服務架構中的服務治理功能。 本文通過簡單的小例子來分享下如何通過Eureka進行服務治理:

Seaborn入門系列()——barplot&countplot&pointplot

微信公眾號:iPythonistas如有問題或建議,請公眾號留言Seaborn是基於matplotlib的Python視覺化庫。 它提供了一個高階介面來繪製有吸引力的統計圖形。Seaborn其實是在matplotlib的基礎上進行了更高階的API封裝,從而使得作圖更加容易

linux入門系列6--軟體管理rpm和yum倉庫

前面系列文章中,我們對vi編輯器和46個基本命令進行了介紹,本文將演示在centos7下使用RPM和YUM安裝和管理軟體。 一、RPM軟體包管理器 1.1 RPM背景介紹 ​ RPM(RedHat Package Manager),類似於windows下的控制面板,而RPM軟體包類似於setup.exe安裝檔

linux入門系列12--磁碟管理分割槽、格式化與掛載

前面系列文章講解了VI編輯器、常用命令、防火牆及網路服務管理,本篇將講解磁碟管理相關知識。 本文將會介紹大量的Linux命令,其中有一部分在“linux入門系列5--新手必會的linux命令”一文中已經介紹,遺忘了或沒學習過的請自行檢視。 磁碟管理主要涉及磁碟擴容以及磁碟配額管理,當伺服器磁碟空間達到一定程度

linux入門系列13--磁碟管理RAID、LVM技術

前一篇文章學習了磁碟分割槽、格式化、掛載等相關知識,本文將講解RAID和LVM技術。 磁碟管理操作主要是運維人員用的較多,如果只是單純的開發人員,可以先略過本文。但是在很多小公司裡往往都是一人多用,運維、開發通常都是同一個人,因此對個人的技能要求更高。即便不是如此,多瞭解下相關概念也是有利而無害的。 本文將先

linux入門系列15--檔案傳輸vsftp服務

前面的系列文章基本講完了linux管理相關的基礎知識,從本篇開始講解centos7中服務程式的部署和配置,以便為外部提供各種服務。 日常工作和娛樂中,我們所需的各種資源都離不開網路以及各種服務,我們通過網路獲取部署在其他伺服器上的各種服務資源,這些服務包括檔案服務、郵件服務、媒體服務等等。 一般情況下,我們使

linux入門系列16--檔案共享Samba和NFS

前一篇文章“linux入門系列15--檔案傳輸之vsftp服務”講解了檔案傳輸,本篇繼續講解檔案共享相關知識。 檔案共享在生活和工作中非常常見,比如同一團隊中不同成員需要共同維護同一個文件,在windows環境下,通常會選用第三方協作工具,如騰訊文件,石墨文件等等。 之前講解了基於ftp的檔案傳輸,為何還會單

linux入門系列17--郵件系統Postfix和Dovecot

前文演示了通過Samba和NFS實現檔案共享,本篇演示使用Postfix和Dovecot在區域網實現電子郵件收發系統。 電子郵件系統是我們日常生活和工作中非常重要的一個網路服務,在windows下收發電子郵件系統工具很多,相信大家一定接觸過,比如qq郵箱、163郵箱等等。本文講解在Linux下通過部署Pos

linux入門系列18--Web服務Apache服務1

前面系列文章講解了Linux下通過檔案傳輸、檔案共享、郵件系統來分享和獲取資源,本文講解網路資源獲取和共享的另外一種形式,通過Apache服務程式來提供Web服務。 本文先講解目前主流的Web服務程式以及各自的特點和優勢,然後以Apache服務為例講解Linux下Web網站的部署,並在部署過程中穿插講解SE

linux入門系列18--Web服務Apache服務2

接上一篇文章,在瞭解Apache基本配置以及SELinux相關知識後,繼續演示Apache提供的虛擬主機功能以及訪問控制方式。 如果還沒看上一篇的建議先檢視後再來,上篇文章“linux入門系列18--web服務之apache服務1”。 三、Apache虛擬主機功能 如果早期你部署過網站,相信一定知道虛擬機器主