DFS技巧有關的訓練題

以下所有代碼均去掉板子

這個是板子

#include<iostream>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<map>
#include<vector>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<ctime>
using namespace std; 
#define rep(i,aa,bb) for(register int i=aa;i<=bb;i++)
#define rrep(i,aa,bb) for(register int i=aa;i>=bb;i--)
#define mset(var,val)	 memset(var,val,sizeof(var))
#define LL long long 
#define eps 0.000001
#define inf 0x7f7f7f7f
#define llinf 1e18
#define exp 0.000001
#define pai 3.141592654
#define random(x)   rand()%(x)
#define lowbit(x)   x&(-x)
inline int read()
{
	int x=0,y=1;char a=getchar();while ( a>'9' || a<'0'){if ( a=='-')y=-1;a=getchar();}
	while ( a>='0' && a<='9' ){	x=(x<<3)+(x<<1)+a-'0'; a=getchar();}return x*y;
}

一、ZOJ 2172 Symmetric Order

題意:

給一些字符串,按照特定順序輸出。

題解:

dfs回溯的順序。或者奇偶順序。
以下是核心代碼(去掉了板子)

#define N 19
int n; char a[N][26];
void dfs(int dep){
	if ( dep == n/2 + 1 ){
		if ( n & 1 == 1 ){
			printf("%s\n",a[n]);
		}
		return ; 
	}
	printf("%s\n",a[dep*2-1]);	
	dfs(dep+1);
	printf("%s\n",a[dep*2]);		
}
int main()
{
	srand((int)time(0));
	int tot = 0 ; 
	while ( scanf("%d",&n) != EOF && n ){
		printf("SET %d\n",++tot);
		rep(i,1,n){
			scanf("%s",a[i]);
		}
		dfs(1);		
	}
	return 0;
}

二、HDU - 1312 Red and Black

題意:

一個人被困在方形迷宮內,起點是@,能走的地方是‘.’也就是黑格,不能走的地方是#也就是紅格。求這個人踩到多少個黑格?

input
6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0
output
45
59
6
13

題解一:

基礎dfs,子問題求解。

int n,m;char ma[50][50];
int dfs(int x,int y){
	if ( x < 0 || x >= n )	return 0 ; 
	if ( y < 0 || y >= m )	return 0 ; 
	if ( ma[x][y] == '#')	return 0 ; 
	ma[x][y] = '#';
	return 1+dfs(x-1,y)+dfs(x+1,y)+dfs(x,y-1)+dfs(x,y+1);
}
int main()
{
	while ( scanf("%d%d",&m,&n) != EOF ){
		rep(i,0,n-1)	scanf("%s",ma[i]);	
		rep(i,0,n-1)	rep(j,0,m-1){
			if ( ma[i][j] == '@' ){
				printf("%d\n",dfs(i,j));
			}
		}
	}
    return 0;
}

題解二:

基礎bfs,多狀態計數。

int n,m;char ma[50][50];
struct node {
	int x,y; 
	node (){	}
};
int nx[4][2]={
1,0,-1,0,0,1,0,-1
};
queue<node>q; int ans = 0 ; bool vis[50][50];
int bfs(int x,int y){ 
	node aaa; aaa.x = x; aaa.y = y; 	q.push(aaa);
	vis[x][y] = 1; 	ans++; 
	while ( !q.empty() ) {
		node a = q.front(); q.pop() ; node b; 
		for (int i = 0; i < 4; i++){
			b.x = a.x + nx[i][0];
			b.y = a.y + nx[i][1];
			if ( b.x>=0 && b.x<n && b.y>=0 && b.y<m && !vis[b.x][b.y] && ma[b.x][b.y]!='#' ){
				vis[ b.x ][ b.y ] = 1; 
				ans++; 
	 			q.push(b); 				
			}
		}
	}
	return ans; 
}
int main()
{
	while ( scanf("%d%d",&m,&n) != EOF ){
		while ( !q.empty() )	q.pop();
		ans = 0 ; 		mset(vis,0);				mset(ma,0);
		rep(i,0,n-1)	scanf("%s",ma[i]);	
		rep(i,0,n-1)	rep(j,0,m-1){
			if ( ma[i][j] == '@' ){
				printf("%d\n",bfs(i,j));
				break; 
			}
		}
	}
    return 0;
}

三、luogu P1120 小木棍(POJ 1011 Sticks)

題意:

喬治有一些同樣長的小木棍,他把這些木棍隨意砍成幾段,直到每段的長都不超過50。
現在,他想把小木棍拼接成原來的樣子,但是卻忘記了自己開始時有多少根木棍和它們的長度。
給出每段小木棍的長度,編程幫他找出原始木棍的最小可能長度。

input
9
5 2 1 5 2 1 5 2 1
output
6

題解:

雙階段dfs,加極限剪枝。

    sort(a+1,a+n+1,cmp);

剪枝一:
排序。 木棍由大到小排序。理由:長度小,而且數量多的木棍,相比於同樣總長的,長度大,數量少的木棍,更加靈活。例如:5和4能組成9。5,2,1和1也能組成9,但是如果當前在組第3組木棍,還有兩組木棍要組合,那麼我肯定優先選擇5和4,這樣,才能把更多可能性給第4組和第5組,第4組和第5組才更有可能組成長度爲規定的長木棍。

			while ( a[i] == a[i+1] )	
				i++;	

剪枝二:
去重。a[i] 有相同值時候,我們只dfs第一個值(在dep層dfs),下一個階段(在dep+1層)我們會dfs,a[i+1],(在dep+2層)dfs,a[i+2]。如果在dep層dfs,a[i+1],那麼會多次枚舉,走相同的dfs。每一層都多走,相當浪費時間資源。

			if ( len == a[i] || len == pp )
				return 0 ; 

剪枝三:
當我們枚舉的這根長木棍剩餘值,正好等於,當前枚舉的a[i]時,我們用a[i]填補枚舉的這根長木棍,如果,a[i]以後的短木棍都無法拼湊成剩下的長木棍,那麼我們用比a[i]更小的短木棍更不可能拼湊成剩下的長木棍。栗子:len5,pp6,a[i] == 5 ,剩下的短木棍爲4,4,3。代入驗證即可。
剪枝四:
當前a[i]放到,當前枚舉的長木棍中(當前長木棍未放入任何值)之後,都無法拼接剩下的長木棍,那麼,pp這個值肯定是無法使用的。

    if ( len < a[cnt] )		return 0 ;

剪枝五:
現在需要的短木棍長度,比最短的那個短木棍還小。那麼pp的值不合適。

bool cmp(int x,int y)
{
    return x>y;
}
int n,t,sum=0,cnt=0,a[70],res,vis[70],pp;
int dfs(int len,int sta,int now){
	if ( now == res ){
		return 1; 
	}
	if ( len == 0 )
		if ( dfs(pp,1,now+1) )
			return 1;
    if ( len < a[cnt] )		return 0 ;   			
	for (int i = sta; i <= cnt ; i++){
		if ( !vis[i] && a[i] <= len ){
			vis[i] = 1;
			if ( dfs(len-a[i],i+1,now) )
				return 1; 	 
			vis[i] = 0;
			if ( len == a[i] || len == pp )
				return 0 ; 
			while ( a[i] == a[i+1] )	
				i++;	
		}
	}	
	return 0 ;	
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&t);
        if(t<=50)
        {
            sum+=t;
            a[++cnt]=t;
        }
    }
    sort(a+1,a+n+1,cmp);
    for(int i=a[1];i<=sum/2;i++)
        if(sum%i==0)
        {
            pp=i; // 全局記錄長度 
            res=sum/i;
            if(dfs(i,1,0))
            {
                printf("%d",i);
                return 0;
            }
        }
    printf("%d",sum);    
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章