1. 程式人生 > >hdu 1045 貪心回溯

hdu 1045 貪心回溯

第一次理解遞迴的含義,並且應用起來。如在這個題目裡,我一開始有好幾種想法,但都和自己手動模擬的不一樣。
大意:給出一個地圖,x表示牆,任何武器都不能穿過,.表示空地,在空地上可以建炮樓,每個炮樓都可以攻擊到東西南北方向上的炮樓,前提是不能有牆擋著,在各個炮樓不能相互攻擊的情況下,最多能建多少個炮樓。

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

我們以測試資料

說明<==>就是等價的意思

2
..
..
為例,來簡單的解釋這個經典的問題。從dfs(0,0)開始,也就是讀取資料map[0][0],然後檢查它的上面和左邊有沒有b,顯然符合條件,接下來執行dfs(1,1)讀取map[0][1],由於map[0][0]已經是b了,所以不符合check==1,執行dfs(pos+1,sum)<==>dfs(2,1)檢查map[1][0],同樣由於map[0][0]已經是b,故check!=1,接著執行dfs(pos+1,sum)<==>dfs(3,1)檢查map[1][1],可以使check==1,故可以執行map[1][1]=b,dfs(pos+1,sum+1)<==>dfs(4,2),重點就在於這裡,這也是絕大多貪心演算法的難點,當pos==4是,會執行第一個if操作,並把最大的sum值保留下來,這時我們的題目要求,然後就return ;這句話我是半天沒想明白,現在終於有點感覺了,這個if判斷是結束當前活動點,注意下一個活動點所必需的,還有我們要明白這個return語句返回到什麼位置,規則是從哪裡來回到哪裡去,dfs(4,2)是怎麼來的呢,是由於dfs(3,1)符合check==1而來的,所以return就返回到dfs(3,1),也就是說這次我計算機記住你了,你dfs(4,2)是一個大坑,是騙人的,那我就不考慮你的先決條件了(check==1),但沒有辦法啊,誰叫我是一根筋呢!那還得執行從dfs(3,1)到dfs(pos+1,sum)<==>dfs(4,1),哇,直接就可以比較pos==n,這裡1比2小,就忽略了,但還得返回return啊,這次熊孩子要跑哪去,你猜猜?還是上面的規則,從哪裡來到哪裡去,熊孩子就得長記性,dfs(3,1)的兩個子條件都不符合,故dfs(3,1)要返回到它來的地方dfs(2,1),但是dfs(2,1)的兩個子條件也都不符合,沒辦法它也得回去,dfs(2,1)是誰派出來的,當然是dfs(1,1)了,它自己本身同樣沒有什麼本事,還得找他的頭dfs(0,0),也就是說從dfs(4,1)一直返回到了dfs(0,0),並把map[0][0]有原來的"b"賦值為"."(這就是著名的回溯),接下來怎麼辦呢?聰明的讀者,自己想想。------執行dfs(pos+1,sum)<==>dfs(1,0),如此迴圈下去,最大的方案數已經存放在ans中了。

接下來是完整的copy大神的程式碼,後面附有自己為了弄明白dfs過程的除錯資料,對自己的理解很有幫助!

/*************************************************************************
     File Name: 1045.cpp
     Author: yubo
     Mail: [email protected] 
     Created Time: 2014年04月13日 星期日 22時26分40秒
     學習重點:
 ************************************************************************/

#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
int ans;//標記個數
char map[10][10];
int n;
int check(int r,int c)
{
	int flag=1,i;
	for(i=r;i>=0;i--){//從[r][c]的上面開始查詢
		if(map[i][c]=='X') break;
		if(map[i][c]=='b'){
			flag=0;
			break;
		}
	}
	for(i=c;i>=0;i--){//從[r][c]的左邊開始查詢 
		if(map[r][i]=='X') break;
		if(map[r][i]=='b'){
			flag=0;
			break;
		}
	}
	return flag;

	
}
void dfs(int pos,int sum)
{
	int r=pos/n,c=pos%n;//計算所檢查的位置
//	printf("pos=%d sum=%d r=%d c=%d \t",pos,sum,r,c);
	if(pos==n*n){//什麼意思呢,感覺pos永遠不會和n*n相等阿
		if(sum>ans)//會的,這樣會把當前的活動點乾死,執行這句dfs(pos+1,sum)
			ans=sum;
		return ;
	}
	if(map[r][c]=='.'){
		if(check(r,c)==1){//符合題目要求的話
			map[r][c]='b';//表示建立一個blockhouse
			dfs(pos+1,sum+1);//向下尋找,同時sum+1
			map[r][c]='.';//這裡我就不懂了,為什麼要新增這一步哪
//			printf("2r=%d 2pos=%d sum=%d\n",r,pos,sum);//有大用,這句話是回溯時恢復原來的狀態

		}
	}
	dfs(pos+1,sum);//只是pos移動,其他沒有變化
	
}
int main()
{
	//freopen("in.txt","r",stdin);
	int i;
	while(scanf("%d",&n),n){
		ans=0;
		memset(map,0,sizeof(map));
		for(i=0;i<n;i++)
			cin>>map[i];
		dfs(0,0);
		printf("%d\n",ans);
	}
}
同樣以2

..

..

為測試資料

並輸出部分資料你可能有更深刻的理解

/*************************************************************************
     File Name: 1045.cpp
     Author: yubo
     Mail: [email protected] 
     Created Time: 2014年04月13日 星期日 22時26分40秒
     學習重點:
 ************************************************************************/

#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
int ans;//標記個數
char map[10][10];
int n;
int check(int r,int c)
{
	int flag=1,i;
	for(i=r;i>=0;i--){//從[r][c]的上面開始查詢
		if(map[i][c]=='X') break;
		if(map[i][c]=='b'){
			flag=0;
			break;
		}
	}
	for(i=c;i>=0;i--){//從[r][c]的左邊開始查詢 
		if(map[r][i]=='X') break;
		if(map[r][i]=='b'){
			flag=0;
			break;
		}
	}
	return flag;

	
}
void dfs(int pos,int sum)
{
	int r=pos/n,c=pos%n;//計算所檢查的位置
	printf("pos=%d sum=%d r=%d c=%d \t",pos,sum,r,c);
	if(pos==n*n){//什麼意思呢,感覺pos永遠不會和n*n相等阿
		if(sum>ans)//會的,這樣會把當前的活動點乾死,執行這句dfs(pos+1,sum)
			ans=sum;
		return ;
	}
	if(map[r][c]=='.'){
		if(check(r,c)==1){//符合題目要求的話
			map[r][c]='b';//表示建立一個blockhouse
			dfs(pos+1,sum+1);//向下尋找,同時sum+1
			map[r][c]='.';//這裡我就不懂了,為什麼要新增這一步哪
			printf("2r=%d 2pos=%d sum=%d\n",r,pos,sum);//有大用,這句話是回溯時恢復原來的狀態

		}
	}
	dfs(pos+1,sum);//只是pos移動,其他沒有變化
	//printf("pos=%d sum=%d\t",r,c);
}
int main()
{
	freopen("in.txt","r",stdin);
	int i;
	while(scanf("%d",&n),n){
		ans=0;
		memset(map,0,sizeof(map));
		for(i=0;i<n;i++)
			cin>>map[i];
		dfs(0,0);
		printf("%d\n",ans);
	}
}
中間過程資料;
pos=0 sum=0 r=0 c=0 	pos=1 sum=1 r=0 c=1 	pos=2 sum=1 r=1 c=0 	pos=3 sum=1 r=1 c=1 	pos=4 sum=2 r=2 c=0 	2r=1 2pos=3 sum=1
pos=4 sum=1 r=2 c=0 	2r=0 2pos=0 sum=0
pos=1 sum=0 r=0 c=1 	pos=2 sum=1 r=1 c=0 	pos=3 sum=2 r=1 c=1 	pos=4 sum=2 r=2 c=0 	2r=1 2pos=2 sum=1
pos=3 sum=1 r=1 c=1 	pos=4 sum=1 r=2 c=0 	2r=0 2pos=1 sum=0
pos=2 sum=0 r=1 c=0 	pos=3 sum=1 r=1 c=1 	pos=4 sum=1 r=2 c=0 	2r=1 2pos=2 sum=0
pos=3 sum=0 r=1 c=1 	pos=4 sum=1 r=2 c=0 	2r=1 2pos=3 sum=0
pos=4 sum=0 r=2 c=0 	2



相關推薦

hdu 1045 貪心回溯

第一次理解遞迴的含義,並且應用起來。如在這個題目裡,我一開始有好幾種想法,但都和自己手動模擬的不一樣。 大意:給出一個地圖,x表示牆,任何武器都不能穿過,.表示空地,在空地上可以建炮樓,每個炮樓都可以攻擊到東西南北方向上的炮樓,前提是不能有牆擋著,在各個炮樓不能相互攻擊的情

hdu 1045 Fire Net(回溯搜尋)

搜尋,回溯!!!人的一生避免不了會犯一些小錯誤!!! 那麼犯錯錯誤可以回頭的!不可以一直錯下去的!!! #include<stdio.h> #include<string.h> int visit[10][10]; char map[10][10];

hdu 6180貪心

bsp urn end 時間排序 有一個 判斷 對比 efi 起點 題意:有m個工程,一臺機器在同一時間只能運行一個工程,告訴你每個工程的起始時間和結束時間,求出最少要多少個機器以及最小的機器總運行時間(機器開始了就不能停了,知道用完該臺機器才停止)。 題解:由於這裏可以

hdu 6188 貪心

ack make printf ace 順子 comment inf -s memset hdu 6188 Duizi and Shunzi 題意:求一個序列中對子和順子的數量。 tags:優先組成對子。對於1 2 3 3 4 5 這樣的先判一下。 #inc

HDU-1045,Fire Net-純暴力簡單DFS】

n! closed 實現 problem 由於 gif open pan alt 原題鏈接:點擊! 大致題意:白塊表示可以放置炮臺的位置——每個炮臺可以攻擊到上下左右的直線上的炮臺(也就是說在它的上下左右直線上不可以再放置炮臺,避免引起互相攻擊),黑塊表示隔離墻的位置

hdu-6301-貪心

arch xtra ret sin title elements php continue earch Distinct Values Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K

hdu-6438-貪心

inf cat show col .cn 獲得 day 隊列 esc Buy and Resell Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tot

HDU - 1045】Fire Net (dfs 或二分圖)

題幹: Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a str

hdu 1045 Fire Net 【二分圖匹配】

進行 col numbers res clu 意思 archive 多少 color <題目鏈接> <轉載於 >>> > 題目大意: 這題意思是給出一張圖,圖中‘X‘表示wall,‘.‘表示空地,可以放置炮臺,同一條直線上只

HDU - 1045 A - Fire Net

Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13947 &nb

HDU 1045 Fire Net 【連通塊的壓縮 二分圖匹配】

題目:http://acm.hdu.edu.cn/showproblem.php?pid=1045 Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav

hdu 1045(dfs類似8皇后)

Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 15746 &nb

HDU 1045 Fire Net 二分圖建圖

HDU 1045 題意:   在一個n*n地圖中,有許多可以擋住子彈的牆,問最多可以放幾個炮臺,是的炮臺不會相互損害。炮臺會向四面發射子彈。 思路:   把行列分開做,先處理行,把同一行中相互聯通的點縮成一個點。再處理列,同樣縮成一個點。然後把行列中,交點不是牆的點連一條邊。對這個圖跑網路流或者二分圖

dfs HDU 1045

Problem Description Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each repr

HDU 4864 貪心

  要求:有n臺機器和m個任務,並且每臺機器和每個任務都帶有一個時間標記和一個等級標記,只有機器的兩個標記都大於任務時才能進行該任務。最大等級不超過100,完成一個任務獲得錢數為500*時間+2*等級。一臺機器一天只能完成一個任務,求完成最大任務數,若有多解,取賺錢數最多的。 方法

HDU 1045 Fire Net

題目連結:傳送門 Problem Description Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and

HDU-1045 Fire Net

可以直接dfs暴搜,也可以轉化為二分圖匹配問題 每一行連續的片段可以縮為一個點,列上連續的片段也是,因為連續的片段最多放一個點 就分為行片段,列片段兩部分,他們的交點就是邊,求最大匹配就是最多可以放的點 dfs暴搜程式碼: #include<iostream&g

HDU 1009 貪心

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 96673 Accepted Submiss

HDU - 1789貪心

#include<iostream> #include<cstring> #include<cstdio> #include<string> #include<algorithm> #include<queue> #incl

hdu 1789 貪心 優先佇列

Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher g