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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章