两个吃奶一个添下面视频_人妻第一页香蕉网_欧美xxxx少妇_妺妺窝人体色www婷婷

本文是講解狀態(tài)壓縮DP的第二部分,仍然是對(duì)基于連通性問(wèn)題的探討與學(xué)習(xí)。一些概念性的問(wèn)題,以及基本解法 在第一節(jié)中講過(guò),這里就不再贅述。

對(duì)典例蒙德里安的夢(mèng)想的分析直接看例題:

求把 N×M 的棋盤(pán)分割成若干個(gè) 1×2 的長(zhǎng)方形,有多少種方案。

例如當(dāng) N=2,M=4 時(shí),共有 5 種方案。當(dāng) N=2,M=3 時(shí),共有 3 種方案。

如下圖所示:

例題

輸入格式

輸入包含多組測(cè)試用例。

每組測(cè)試用例占一行,包含兩個(gè)整數(shù) N 和 M。

當(dāng)輸入用例 N=0,M=0 時(shí),表示輸入終止,且該用例無(wú)需處理。

輸出格式

每個(gè)測(cè)試用例輸出一個(gè)結(jié)果,每個(gè)結(jié)果占一行。

數(shù)據(jù)范圍

1≤N,M≤11

輸入樣例:

1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0

輸出樣例:

1
0
1
2
3
5
144
51205

算法分析:

1. 拿到題目,我們先從暴力的角度思考,如果我們暴力枚舉每一個(gè)格子,那么時(shí)間復(fù)雜度為2^121, 是會(huì)超時(shí)的,因此考慮用記憶化搜索來(lái)優(yōu)化, 于是我們用動(dòng)態(tài)規(guī)劃來(lái)考慮這個(gè)問(wèn)題。

2. 性質(zhì)挖掘:同時(shí),這里我們可以發(fā)現(xiàn)一個(gè)性質(zhì):先將所有橫著的小方塊擺滿(mǎn)再放豎著的小方塊,方案數(shù)和總方案數(shù)是相等的,因?yàn)楫?dāng)所有橫著的合法小方塊放完后,豎著的小方塊只需往空里塞即可,這一點(diǎn)可以從樣例觀(guān)察到。

核心:先放橫著的,再放豎著的。

3. 若我們按列枚舉放小方塊,可以發(fā)現(xiàn),

(1)在第i列放橫著小方塊的方案會(huì)受到第i - 1列的影響;

(2)并且若在同一個(gè)狀態(tài)i中,上一個(gè)小方塊和下一個(gè)小方塊之間的空格數(shù)為奇數(shù)時(shí)是不合法的(因?yàn)榭崭駭?shù)奇數(shù)個(gè)時(shí)無(wú)法用豎著的小方格塞滿(mǎn)棋盤(pán),會(huì)留下空缺)

第一種情況,如下圖:

若兩個(gè)方塊重疊時(shí)則該方案是不合法的(圖中為合法情況),

這里我們?cè)O(shè)第i - 1列的方塊的擺放方案狀態(tài)為 k,第 i 列方塊的擺放方案為 j。

第一種情況

第二種情況:

第一種方案是不合法的,因?yàn)樵跔顟B(tài) j 和狀態(tài)k,中間的空格數(shù)為奇數(shù),不能放下豎著的(1 x 2)小方塊

不合適

第二種方案則是合法的 :

第二種方案

4. 接下來(lái),我們思考動(dòng)態(tài)規(guī)劃的一般流程:狀態(tài)表示,以及狀態(tài)計(jì)算,首先是狀態(tài)表示根據(jù)前文的分析,我們這里需要維護(hù)的變量只有三個(gè):

①當(dāng)前在哪一列,②當(dāng)前列的狀態(tài)是什么,③當(dāng)前狀態(tài)方案數(shù)。

所以我們可以定義狀態(tài)表示為f[i][j]

狀態(tài)表示: f[i][j] 表示已經(jīng)將前i - 1列擺好,且從第 i - 1 列伸出到第i 列的狀態(tài)為j 的所有方案

狀態(tài)表示,以及狀態(tài)計(jì)算

接下來(lái)是狀態(tài)計(jì)算由于我們要找的是最后一個(gè)狀態(tài)的不同點(diǎn),而第i - 1列伸到第 i 列的狀態(tài) j 是固定的, 沒(méi)有固定的是第i - 2列伸到第 i - 1列的狀態(tài)

于是,集合的劃分依據(jù)應(yīng)是:i - 2 列延申到 i - 1 列的 狀態(tài)k 來(lái)劃分的;那么,我們上面的圖就應(yīng)該有所更新,表示為:這時(shí),我們?cè)O(shè)第i - 2列的方塊的擺放方案狀態(tài)為k, 第 i - 1列方塊的擺放方案為 j。

第 i - 1列方塊的擺放方案為 j

此時(shí),我們的集合劃分圖像應(yīng)當(dāng)如下

集合劃分圖像

至此,完成所有分析,整體如下:

整體分析圖



代碼如下:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
							//N表行數(shù) 
const int N = 12, M = 1 << N;//M表方案數(shù),一共有二的N次方個(gè) 
 
int n, m;
long long f[N][M]; //狀態(tài)轉(zhuǎn)移方程
vector<int> state[M];  //存儲(chǔ)所有合法狀態(tài) 
bool st[M]; //存儲(chǔ)每種狀態(tài)是否有奇數(shù)個(gè)連續(xù)的0,如果奇數(shù)個(gè)0是無(wú)效狀態(tài)
			//如果是偶數(shù)個(gè)零置為true。
 
 
int main()
{
	while(cin >> n >> m, n ||m)//本題有多個(gè)數(shù)據(jù) 
	{
		//第一部分:預(yù)處理1
		//對(duì)于每種狀態(tài),先預(yù)處理每列不能有奇數(shù)個(gè)0 
		for(int i = 0;i < 1 << n;i ++)//預(yù)處理st數(shù)組,判斷所有連續(xù)的0是否有偶數(shù)個(gè)		 
		{
			int cnt = 0;//cnt 表示0的個(gè)數(shù)
			bool is_valid = true;//是否合法 
			 for(int j = 0;j < n;j ++)//遍歷這一列,從上到下 
			 if(i >> j & 1)//對(duì)于i的二進(jìn)制數(shù)的第j位,判斷是否為1 
			 {
			 	if(cnt & 1)//判斷前面的0是否有奇數(shù)個(gè) 
			 	{
			 		is_valid = false;//不合法 
			 		break;
				 }
				 cnt = 0;//清空 
			  } 
			  else cnt ++;//否則前面是0,cnt++ 
			  if(cnt & 1) is_valid = false;//判斷最下面那一段連續(xù)0的個(gè)數(shù) 
			  st[i] = is_valid;
		}
		
	//第二部分:預(yù)處理2
	//判斷第i - 2列伸出來(lái)的和第i - 1列伸出去的是否沖突
	
	for(int j = 0;j < 1 << n;j ++)//對(duì)于第i列的所有狀態(tài)
	{
		state[j].clear();//清空上次操作遺留的狀態(tài)(因?yàn)楸绢}有while循環(huán),多個(gè)測(cè)試數(shù)據(jù))
		for(int k = 0;k < 1 << n;k ++)//對(duì)于第i-1列的所有狀態(tài) 
		{
			if((j & k)==0 && st[j | k])//若兩者伸出來(lái)的沒(méi)重疊
				state[j].push_back(k);//j | k表示當(dāng)前第i- 1列到底有幾個(gè)1,即哪幾行是放格子的 
									
		 } 
	}
	
	//第三部分:DP
	memset(f,0,sizeof f); //全部初始化為0,因?yàn)槭莣hile連續(xù)讀入 
	
	f[0][0] = 1;//這里沒(méi)有-1列,所以不可能有方塊伸到第0列,因此f[0][0] = 1, 即表示棋盤(pán)為空的一種狀態(tài) 
	
	for(int i =1;i <= m;i ++)//遍歷每一列:第i列合法范圍是(0~m-1列) 
		for(int j = 0;j < 1 << n;j ++)//遍歷當(dāng)前列(i)的所有狀態(tài)j 
			for(auto k: state[j])//遍歷第i-1列的狀態(tài)k,真正滿(mǎn)足則轉(zhuǎn)移 
				f[i][j] += f[i - 1][k];// 當(dāng)前列的方案數(shù)就等于之前的第i-1列所有狀態(tài)k的累加。
	
	//依據(jù)狀態(tài)表示的定義:f[m][0]表示 前m-1列都處理完,并且第m-1列沒(méi)有伸出來(lái)的所有方案數(shù)。
	//即整個(gè)棋盤(pán)處理完的方案數(shù) 
	cout << f[m][0] << endl;			
	}
	
	
	return 0;
}

注:第一部分的預(yù)處理,對(duì)應(yīng)上面分析的第二種情況, 

第一部分的預(yù)處理

第二部分的預(yù)處理,對(duì)應(yīng)上面分析的第一種情況:

第二部分的預(yù)處理

點(diǎn)贊(0)

C語(yǔ)言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競(jìng)賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點(diǎn)擊了解:

一點(diǎn)編程也不會(huì)寫(xiě)的:零基礎(chǔ)C語(yǔ)言學(xué)練課程

解決困擾你多年的C語(yǔ)言疑難雜癥特性的C語(yǔ)言進(jìn)階課程

從零到寫(xiě)出一個(gè)爬蟲(chóng)的Python編程課程

只會(huì)語(yǔ)法寫(xiě)不出代碼?手把手帶你寫(xiě)100個(gè)編程真題的編程百練課程

信息學(xué)奧賽或C++選手的 必學(xué)C++課程

藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競(jìng)賽課入門(mén)課程

手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程

Dotcpp在線(xiàn)編譯      (登錄可減少運(yùn)行等待時(shí)間)