DFS练习

1

 

POJ 1979 Red and Black

Description

There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can't move on red tiles, he can move only on black tiles. 

Write a program to count the number of black tiles which he can reach by repeating the moves described above. 

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20. 

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows. 

'.' - a black tile 
'#' - a red tile 
'@' - a man on a black tile(appears exactly once in a data set) 
The end of the input is indicated by a line consisting of two zeros. 

Output

For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).

Sample Input

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0

Sample Output

45
59
6
13

 

// 红黑两种砖 只能在黑砖上 最多能走多少黑砖

 

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int ans;
int dir[4][2]= {{0,1},{0,-1},{-1,0},{1,0}};
char a[25][25];
int m,n;
void dfs(int x,int y)
{
    a[x][y] = '#';
    ++ans;
    for(int i = 0 ; i < 4; i ++)
    {
        int dx = x + dir[i][0];
        int dy = y + dir[i][1];
        if(dx >= 0 && dx < n && dy >=0 && dy < m && a[dx][dy] == '.')
        {
            dfs(dx,dy);
        }
    }
}
int main()
{
    while(scanf("%d %d",&m,&n)!=EOF&&m&&n)        //  m 列 n 行
    {
        int x,y;
        ans = 0;
            for(int i = 0 ; i < n ; i++)
                for(int j = 0; j < m ;j++)
                {
                    cin>>a[i][j];
                    if(a[i][j] == '@')
                    {
                        x = i;
                        y = j;
                    }
                }
                dfs(x,y);
                printf("%d\n",ans);
        }
    return 0;
}

 

2

 

洛谷 P1605 迷宫

题目背景

迷宫 【问题描述】

给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过。给定起点坐标和

终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫

中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

输入样例 输出样例

【数据规模】

1≤N,M≤5

题目描述

输入输出格式

输入格式:

 

【输入】

第一行N、M和T,N为行,M为列,T为障碍总数。第二行起点坐标SX,SY,终点

坐标FX,FY。接下来T行,每行为障碍点的坐标。

 

输出格式:

 

【输出】

给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方

案总数。

 

输入输出样例

输入样例#1:

2 2 1
1 1 2 2
1 2

输出样例#1: 

1

 

//  数组从1开始存  起点要注意

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int m,n,t,sum;
int sx,sy,fx,fy;
int dir[4][2] ={{0,1},{0,-1},{-1,0},{1,0}};
int a[10][10];
void dfs(int x,int y)
{
    if(x == fx && y == fy)
    {
        ++sum;
        return ;
    }
        for(int i = 0 ; i < 4; i++)
        {
            int dx = x + dir[i][0];
            int dy = y + dir[i][1];
            if(dx >= 1 && dx <= n && dy >= 1 && dy <= m && a[dx][dy] == 1)
            {
                a[dx][dy] = 0;
                dfs(dx,dy);
                a[dx][dy] = 1;
            }
        }
    return;
}
int main()
{
    int l,r;
    sum = 0;
    scanf("%d %d %d",&n,&m,&t);
    for(int i = 1 ; i <= n ; i++)
        for(int j = 1 ; j <= n ; j++)
            a[i][j] = 1;
    scanf("%d %d",&sx,&sy);
    scanf("%d %d",&fx,&fy);
    for(int i = 0 ; i < t; i ++)
        {
            scanf("%d %d",&l,&r);
            a[l][r] = 0;
        }
        a[sx][sy] = 0;      //  起点要标记走过了~
    dfs(sx,sy);
    printf("%d\n",sum);
    return 0;
}

 

333

P1219 八皇后

题目描述

检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。

//以下的话来自usaco官方,不代表洛谷观点

特别注意: 对于更大的N(棋盘大小N x N)你的程序应当改进得更有效。不要事先计算出所有解然后只输出(或是找到一个关于它的公式),这是作弊。如果你坚持作弊,那么你登陆USACO Training的帐号删除并且不能参加USACO的任何竞赛。我警告过你了!

输入输出格式

输入格式:

 

一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。

 

输出格式:

 

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

 

输入输出样例

输入样例#1: 

6

输出样例#1: 

2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

 

//  关键是存储对角线上是否有棋子找到行,列,阶数n的关系 表示出来

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int a[100]={0},b[100]={0},c[100]={0},d[100]={0};    //  行 列 右上到左下 左上到右下 的 对角线
int ans = 0;        //  记录解的个数

void print()
{
    if(ans <= 2)
    {
        for(int k=1;k<=n;k++)
        printf("%d ",a[k]);
        printf("\n");
    }
    ans++;//
}
void dfs(int i)
{
    if(i > n)
    {
        print();
        return ;
    }
    else
    {
        for(int j = 1 ; j <= n ; j++)
        {
            if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))
            {
                a[i] = j;
                b[j] = 1;
                c[i+j] = 1;
                d[i - j + n] = 1;
                dfs(i + 1);
                b[j] = 0;
                c[i+j] = 0;
                d[i - j + n] = 0;
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    dfs(1);
    printf("%d\n",ans);
    return 0;
}

 

 

4444

E - N皇后问题    HDU - 2553 

 

 

在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。 
你的任务是,对于给定的N,求出有多少种合法的放置方法。 
 

Input

共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。

Output

共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。

Sample Input

1
8
5
0

Sample Output

1
92
10

 

 

//  注意该题要提前将数据打好表来做,要不然会超时

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int a[100]={0},b[100]={0},c[100]={0},d[100]={0};    //  行 列 右上到左下 左上到右下 的 对角线
int ans;        //  记录解的个数
int v[15];

void dfs(int i)
{
    if(i > n)
    {
        ans++;
        return ;
    }
    else
    {
        for(int j = 1 ; j <= n ; j++)
        {
            if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))
            {
                a[i] = j;
                b[j] = 1;
                c[i+j] = 1;
                d[i - j + n] = 1;
                dfs(i + 1);
                b[j] = 0;
                c[i+j] = 0;
                d[i - j + n] = 0;
            }
        }
    }
}
int main()
{
    for(n = 1; n <= 10 ; n++)
    {
        ans = 0;
        dfs(1);
        v[n] = ans;
    }

    int w;
    while(scanf("%d",&w)!=EOF&&w)
    {
        printf("%d\n",v[w]);
    }
        return 0;
}

 

 

55

D - Prime Ring Problem    HDU - 1016

A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime. 

Note: the number of first circle should always be 1. 

Input

n (0 < n < 20). 

Output

The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order. 

You are to write a program that completes above process. 

Print a blank line after each case. 

Sample Input

6
8

Sample Output

Case 1:
1 4 3 2 5 6
1 6 5 2 3 4

Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2

 

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int num[100100],v[100100];
int n;
bool isprime(int x)         //  判断是否为质数
{
    for(int i = 2 ; i <= sqrt(x); i++)
        if(x % i == 0)
            return false;
    return true;
}
void dfs(int x)
{
    if(x == n && isprime(num[n - 1]+1))     //  打印
    {
        printf("1");     //  第一位是1
        for(int i = 1; i < n ; i++)
            printf(" %d",num[i]);
        printf("\n");
    }
    for(int i = 2;i <= n ; i++)
    {
        if(!v[i]&&isprime(num[x - 1] + i))
        {
            num[x] = i;
            v[i] = 1;
            dfs(x+1);
            v[i] = 0;
        }
    }
}
int main()
{
    int k = 1;
    while(scanf("%d",&n)!=EOF)
    {
        memset(v,0,sizeof(v));
        num[0] = 1;
        v[1] = 1;     // 标记1被使用
        printf("Case %d:\n",k++);
        dfs(1);
        printf("\n");
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值