1. 程式人生 > >[jzoj3252] 【GDOI三校聯考】炸彈(經典DP)

[jzoj3252] 【GDOI三校聯考】炸彈(經典DP)

Problem

  • 給出一個網格圖,由 01 01 構成,其中 0 0 相連,構成一顆樹.

  • 可以放炸彈,一個炸彈可以覆蓋連續的一行 0

    0 或一列 0 0 .

  • 求放至少多少個炸彈,使得每個 0 0

    都會被至少 1 1 個炸彈覆蓋。

Data constraint

  • n , m
    50 n,m\le 50

Solution

  • 資料範圍很小,加起來就 2500 2500 個點,很容易讓人誤入歧途.

  • 正解實質上是DP

  • 以從左到右,從上到下的順序找到第一個 0 0 ,作為根,依次走下去,形成一顆樹.

  • 考慮每個格子 ( x , y ) (x,y) 的狀態,不妨假設其父親格點是 ( x 1 , y ) (x-1,y)

    • ①:直接在 ( x , y ) (x,y) 這個點放了一個炸彈.
    • ②:由 ( x , y 1 ) , ( x , y + 1 ) (x,y-1),(x,y+1) 轉移過來,即 x x 行放了炸彈,且能影響到 ( x , y ) (x,y) .
    • ③:由 ( x + 1 , y ) (x+1,y) 轉移過來,即在第 y y 列放了炸彈,且能影響到 ( x , y ) (x,y) .
  • 為何要把第二、三種分開討論?

  • 顯然,這是因為 ( x + 1 , y ) (x+1,y) 的影響不僅僅是 ( x , y ) (x,y) ,可能會影響到它父親,父親的父親……

  • 所以,我們首先要把一個點的狀態給分析清楚,即可能有怎樣的決策影響.

  • 分析好狀態,我們不難想到這樣的狀態設計:

    • f [ i ] [ 0 ] f[i][0] :表示以 i i 為根的子樹,沒放炸彈,還剩一條與父親向同向的子樹鏈沒有炸.
    • f [ i ] [ 1 ] f[i][1] :表示以 i i 為根的子樹,子樹炸完了,但沒有炸出去,即父親向的方向上沒有放炸彈.
    • f [ i ] [ 2 ] f[i][2] :表示以 i i 為根的子樹,子樹炸完了,且炸出去了,即父親向的方向上有炸彈.
  • 如此一來,我們便可以很方便的討論轉移了.

  • 具體轉移分成四類,即有 0 , 1 , 2 , 3 0,1,2,3 個兒子時的情況.

  • 這裡以 3 3 個兒子為例,其他是類似的,且 3 3 個兒子也是最複雜的。

不妨設目前轉移點編號為k
其中p[1],p[2],p[3]為k的3個兒子,且p[1]在父親向(上下)的方向上,p[2],p[3]在k點的左右方向上.

那麼必定有:

f[k][0] = min( Min(f[p[2]][0], f[p[2]][1], f[p[2]][2]) + f[p[3]][2], 
			   Min(f[p[3]][0], f[p[3]][1], f[p[3]][2]) + f[p[2]][2]
			  ) + f[p[1]][0];

//f[p[1]][0]是必須要轉移的,因為當前點沒放炸彈,如果要延續,則兒子必須連續
//因為當前點沒有放炸彈,所以“左右”方向上必定有一個是炸出去了的,也就是f[p[2]][2]或f[p[3]][2]必選一個
//另外一個則可以隨便選,所以是取3個min值.

f[k][1] = min( Min(f[p[2]][0], f[p[2]][1], f[p[2]][2]) + f[p[3]][2],
			   Min(f[p[3]][0], f[p[3]][1], f[p[3]][2]) + f[p[2]][2]
			   ) + f[p[1]][1];

//f[p[1]][1]是必須要轉移的,因為當前點也不能放炸彈.
//其餘與上面一種情況完全類似.

f[k][2] = min( (1 + Min(f[p[1]][0], f[p[1]][1], f[p[1]][2]) +
					Min(f[p[2]][0], f[p[2]][1], f[p[2]][2]) +
					Min(f[p[3]][0], f[p[3]][1], f[p[3]][2])), 
				0 + f[p[1]][2] +
				min( Min(f[p[2]][0], f[p[2]][1], f[p[2]][2]) + f[p[3]][2],
				     Min(f[p[3]][0], f[p[3]][1], f[p[3]][2]) + f[p[2]][2])
			);
}

//這裡的轉移就分兩種情況討論了,即當前點放炸彈還是不放.
//看一看,應該還是很好理解的.

  • 對於其餘的三種情況,其實也並不簡單多少,因為還要繼續分類討論,即有沒有上下的這種父親向的兒子.

  • 總之,就是這樣的一個DP:

#include <cstdio>
#include <iostream>

#define F(i, a, b) for (int i = a; i <= b; i ++)
#define Min(a, b, c) ((a) < min(b, c) ? a : min(b, c))
#define num(a, b) ((a - 1) * m + b)

const int N = 51, M = 10 * N * N, dx[4] = {0, - 1, 1, 0}, dy[4] = {- 1, 0, 0, 1}, Impossible = 1e9;

using namespace std;

int n, m, tot, Sx, Sy, f[M][3]; char ch[N][N];
int tov[M], nex[M], las[M], Spe[M], Fa[M];

void ins(int x, int y, int z) {
	tov[++ tot] = y, nex[tot] = las[x], las[x] = tot, Spe[tot] = z;
}

void Dfs(int k, int La) {
	int SonTotal = 0, p[4]; p[0] = p[1] = p[2] = p[3] = 0;
	for (int x = las[k] ; x ; x = nex[x])
		if (tov[x] ^ La)
			Fa[tov[x]] = Spe[x], Dfs(tov[x], k), p[++ SonTotal] = tov[x];
	if (SonTotal == 0) {
		f[k][0] = 0;
		f[k][1] = Impossible;
		f[k][2] = 1;
	}

	if (SonTotal == 1) {
		if (Fa[p[1]] == Fa[k]) {
			f[k][0] = min(f[p[1]][0], f[p[1]][1]);
			f[k][1] = Impossible;
			f[k][2] = min(min(f[p[1]][0], f[p[1]][1]) + 1, f[p[1]][2]);
		}
		else {
			f[k][0] = f[p[1]][1];
			f[k][1] = f[p[1]][2];
			f[k][2] = Min(f[p[1]][0], f[p[1]][1], f[p[1]][2]) + 1;
		}
	}

	if (SonTotal == 2) {
		if (Fa[p[1]] == Fa[k] || Fa[p[2]] == Fa[k]) {
			if (Fa[p[2]] == Fa[k]) swap(p[1], p[2]);

			f[k][0] = min(f[p[2]][1], f[p[2]][2]) + f[p[1]][0];
			f[k][1] = f[p[2]][2] + f[p[1]][1];
			f[k][2] = min( (1 + Min(f[p[1]][0], f[p[1]][1], f[p[1]][
            
           

相關推薦

[jzoj3252] GDOI炸彈經典DP

Problem 給出一個網格圖,由 01 01

JZOJ 1005GDOI2009五公交網路

這題還是有點難度的(像我這種caiji都能推出來的難度) 網上都沒題解 這題放在OJ上9年了都 才9個人做 (好吧是dalao們不想做) 於是經過本弱三天(一天一小時健康一輩子)的努力 把這題弄掉了QAQ 好了先放題目 Description 在世界某個安靜的角落,N 只毛毛

平衡樹2018國慶D3T3

分析: #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<assert.h> #def

資料結構線段樹2018國慶D5T3

題意: 分析: 有一個顯然的暴力方法: 對每個詢問,從左往右做一次,記錄字首和,當某個位置字首和為負後,則刪去當前點。再從右往左做一次。 考慮使這個過程變得高效: 可以將詢問按左端點從右往左排序,然後用棧依次處理每個在從左往右考慮時是否需要刪除。 再利用線段樹,求

圖論2018國慶D5T2

分析: 題意非常醜陋。。。簡化出來就一句話:每個點有選中、未選中兩種狀態,現在給出一些矛盾關係,要求加入儘可能少的矛盾關係,使得沒有合法方案。 如此2sat的模型,顯然需要2sat的連邊方式。。。然後直接列舉每個位置選、不選是否合法即可。若不選合法,則考慮其練的邊是否有一個

數論2018國慶D4T2

題意: 很簡單,給出正整數 n ,求出 n! 在十進位制表示下的從最末非零位開始的總共 k 位。 n ≤

DP1017T3

題意: 分析: 考場上這題做了我兩個小時。。。果然第一步都錯了。。。 首先,所謂的絕對值其實可以用最優性忽略!!!! 即:|a-b|=max(a-b,b-a) 所以,不必考慮到底誰大誰小,在最優策略中,一定是合法的。 然後就很簡單了:每一個位置的貢獻分別可能為2,0,-

DP1017T2

分析 非常水的np狀態轉移的題 定義 D P [

莫隊連結串列1015T3

題意: 分析: 啊啊啊啊我發明的演算法居然以前有過。。。。https://blog.csdn.net/qq_34454069/article/details/80184286 方法其實很簡單。。。首先,把所有未加入的點放在一個雙向連結串列裡。 然後,每次插入一

10.24點亮

@點亮@ @問題描述@ @分析1 - 隨機的性質@ @分析2 - 利用性質@ @演算法細節@ @程式碼@ @證明(過於枯燥)@ @[email protected] @

DP2018國慶

題意: 在N個格子之間,放入D-1個隔板(可以重合),要求每兩個相鄰隔板之間距離不超過M。求方案數。 N,M≤2000N,M\leq 2000N,M≤2000 D≤1012D\leq 10^{12}D≤

DP概率與期望2018國慶D3T2

題意: 分析: #include<cstdio> #include<cstring> #include<algorithm> #include<cma

資料結構線段樹字串Hash2018國慶D4T3

題意: 分析: 題解見標籤 (不過這題有非正解方法可以卡過去。。我程式碼附在下面) 正解: #include<cstdio> #include<cstring> #inclu

組合數學DP 10.15 —— Chess

題目描述 dirty 在一個棋盤上放起了棋子。 棋盤規格為 n ∗ m,他希望任意一個 n ∗ n 的區域內都有 K 個棋子。dirty 很快就放置好了一 個滿足條件的棋盤方案,但是他認為這樣過於簡單了

圖論DFS10.20T2

題意 尋找有多少條邊滿足:圖中所有奇環都包含這條邊,且這條邊不屬於任何偶環 分析: 最後一個性質好坑。。。一直在想那個性質結果T3都沒來得及做… 直接建一個DFS樹。因為是無向圖,所以只存在樹邊和返祖

比賽題解FJ NOIP 四 2017 Round 7

快速 高度 str height size 都是 png logs h+ 此次比賽為廈門一中出題。都是聚勞,不敢恭維。 莫名爆了個0,究其原因,竟然是快讀炸了……很狗,很難受。 話不多說,來看看題: 【T1】 題意: 樣例: PS:1<=h[i]<=1000

鍛造

max -m i++ 預處理 csharp gin 怎麽 垃圾 getc 題目描述 “歡迎啊,老朋友。” 一陣寒暄過後,廠長帶他們參觀了廠子四周,並給他們講鍛造的流程。 “我們這裏的武器分成若幹的等級,等級越高武器就越厲害,並且對每一等級的武器都有兩種屬性值 b 和 c,但

JZOJ3853NOIP2014八第2場第2試9.28幫助Bsny(help)

EVRT Bsny的書架亂成一團了,幫他一下吧! 他的書架上一共有n本書,我們定義混亂值是連續相同高度書本的段數。例如,如果書的高度是30,30,31,31,32,那麼混亂值為3;30,32,32,

2017杭二 圖的有向環

tor gist fin lin def clu pro script space P2555 - 【2017杭二聯考】圖的有向環 Description 題目背景: 幻想鄉的亡靈公主,西行寺幽幽子,在幻想鄉很受歡迎,經常有妖怪來拜訪她,但是幽 幽子並不喜歡被打擾

NOIP2018--電壓機制(voltage)

很容易發現與奇環和偶環有關,但是仔細想清楚和怎麼用程式實現還是很難的 但是我們dfs一邊後,會發現能形成環的邊都變成了返祖邊 而且這些返祖邊對於答案大部分情況下都沒有貢獻 偶環上的邊都不能做出貢獻,當且僅當一條邊被所有奇環包含時才能做出貢獻 有兩個性質