poj1872A Dicey Problem(迭代加深dfs)

A Dicey Problem
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 788 Accepted: 271

Description

The three-by-three array in Figure 1 is a maze. A standard six-sided die is needed to traverse the maze (the layout of a standard six-sided die is shown in Figure 2). Each maze has an initial position and an initial die configuration. In Figure 1, the starting position is row 1, column 2-the "2" in the top row of the maze-and the initial die configuration has the "5" on top of the die and the "1" facing the player (assume the player is viewing the maze from the bottom edge of the figure). 

To move through the maze you must tip the die over on an edge to land on an adjacent square, effecting horizontal or vertical movement from one square to another. However, you can only move onto a square that contains the same number as the number displayed on the top of the die before the move, or onto a "wild" square which contains a star. Movement onto a wild square is always allowed regardless of the number currently displayed on the top of the die. The goal of the maze is to move the die off the starting square and to then find a way back to that same square. 

For example, at the beginning of the maze there are two possible moves. Since the 5 is on top of the die, it is possible to move down one square, and since the square to the left of the starting position is wild it is also possible to move left. If the first move chosen is to move down, this brings the 6 to the top of the die and moves are now possible both to the right and down. If the first move chosen is instead to the left, this brings the 3 to the top of the die and no further moves are possible. 

If we consider maze locations as ordered pairs of row and column numbers (row, column) with row indexes starting at 1 for the top row and increasing toward the bottom, and column indexes starting at 1 for the left column and increasing to the right, the solution to this simple example maze can be specified as: (1,2), (2,2), (2,3), (3,3), (3,2), (3,1), (2,1), (1,1), (1,2). A bit more challenging example maze is shown in Figure 3. 

The goal of this problem is to write a program to solve dice mazes. The input file will contain several mazes for which the program should search for solutions. Each maze will have either a unique solution or no solution at all. That is, each maze in the input may or may not have a solution, but those with a solution are guaranteed to have only one unique solution. For each input maze, either a solution or a message indicating no solution is possible will be sent to the output. 

Input

The input file begins with a line containing a string of no more than 20 non-blank characters that names the first maze. The next line contains six integers delimited by single spaces. These integers are, in order, the number of rows in the maze (an integer from 1 to 10, call this value R), the number of columns in the maze (an integer from 1 to 10, call this value C), the starting row, the starting column, the number that should be on top of the die at the starting position, and finally the number that should be facing you on the die at the starting position. The next R lines contain C integers each, again delimited by single spaces. This R * C array of integers defines the maze. A value of zero indicates an empty location in the maze (such as the two empty squares in the center column of the maze in Figure 3), and a value of -1 indicates a wild square. This input sequence is repeated for each maze in the input. An input line containing only the word "END" (without the quotes) as the name of the maze marks the end of the input.

Output

The output should contain the name of each maze followed by its solution or the string "No Solution Possible" (without the quotes). All lines in the output file except for the maze names should be indented exactly two spaces. Maze names should start in the leftmost column. Solutions should be output as a comma-delimited sequence of the consecutive positions traversed in the solution, starting and ending with the same square (the starting square as specified in the input). Positions should be specified as ordered pairs enclosed in parentheses. The solution should list 9 positions per line (with the exception of the last line of the solution for which there may not be a full 9 positions to list), and no spaces should be present within or between positions.

Sample Input

DICEMAZE1
3 3 1 2 5 1
-1 2 4
5 5 6
6 -1 -1
DICEMAZE2
4 7 2 6 3 6
6 4 6 0 2 6 4
1 2 -1 5 3 6 1
5 3 4 5 6 4 2
4 1 2 0 3 -1 6
DICEMAZE3
3 3 1 1 2 4
2 2 3
4 5 6
-1 -1 -1
END

Sample Output

DICEMAZE1
  (1,2),(2,2),(2,3),(3,3),(3,2),(3,1),(2,1),(1,1),(1,2)
DICEMAZE2
  (2,6),(2,5),(2,4),(2,3),(2,2),(3,2),(4,2),(4,1),(3,1),
  (2,1),(2,2),(2,3),(2,4),(2,5),(1,5),(1,6),(1,7),(2,7),
  (3,7),(4,7),(4,6),(3,6),(2,6)
DICEMAZE3
  No Solution Possible

Source


题目大意:给一个地图,n*m的,地图上每个点有相应的数字,-1~6,-1代表空地,0代表障碍。现在给你一个骰子,如果骰子旁边的位置上的数字恰好等于当前骰子状态的上表面的点数或者旁边是空地,则骰子可以滚动到该位置。给你初始骰子的位置以及初始骰子的状态,求能否找到一条路径使骰子走一圈后又回到起点,如果有,按要求输出路径。
题目分析:dfs输出路径问题。由于深度未知,可以用迭代加深dfs。每个骰子有24个状态,可以枚举出来,只要定了骰子的上表面和前表面,骰子的状态其实就已经定了,所以可以用四维数组判重。理论上一共有24*m*n个状态,但是最后经过测试发现其实深度2*m*n也能过。最后再经过测试发现其实不用设置深度也能过。dfs遍历答案是唯一的,题目好像说了如果有解保证是唯一解。
这题输出有点搞人,小心PE,虽然我没有PE。
最后隆重友情鸣谢峰峰、吉吉两位小朋友,帮我找出本题最大的trick:搜索的时候起点不能标记!!如果标记了样例虽然能过,但是有的例子是过不了的,所以会WA,过不了是因为有的测试数据回到起点的状态和初始状态会一样,如果一开始就把起点标记了,就回不到起点了。。。。
详情请见代码:
#include <iostream>
#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
const int N = 12;
bool flag[N][N][N][N];//
int map[N][N];
bool ok;
int path[105][2];
char s[25];
//u,d,f,b,l,r   24state
int die[][6] = {
                {1,6,2,5,3,4},{1,6,3,4,5,2},{1,6,5,2,4,3},{1,6,4,3,2,5},
                {2,5,1,6,4,3},{2,5,4,3,6,1},{2,5,6,1,3,4},{2,5,3,4,1,6},
                {3,4,1,6,2,5},{3,4,2,5,6,1},{3,4,6,1,5,2},{3,4,5,2,1,6},
                {4,3,1,6,5,2},{4,3,5,2,6,1},{4,3,6,1,2,5},{4,3,2,5,1,6},
                {5,2,1,6,3,4},{5,2,3,4,6,1},{5,2,6,1,4,3},{5,2,4,3,1,6},
                {6,1,2,5,4,3},{6,1,4,3,5,2},{6,1,5,2,3,4},{6,1,3,4,2,5},
};
int n,m,si,sj,up,fa;
int ctrl;

void dfs(int curi,int curj,int dp,int u,int d,int f,int b,int l,int r)
{
    if(dp > ctrl)
        return;
    if(ok)
        return;
    if(flag[curi][curj][u][f])
        return;
    if(dp)
        flag[curi][curj][u][f] = 1;
    path[dp][0] = curi;
    path[dp][1] = curj;
    if(curi == si && curj == sj && dp)
    {
        int i,j;
        for(i = 0;i <= dp;i ++)
        {
            if(i % 9 == 0)
                printf("  ");
            if((i + 1) % 9)
            {
                printf("(%d,%d)",path[i][0],path[i][1]);
                if(i < dp)
                    putchar(',');
            }
            else
            {
                printf("(%d,%d)",path[i][0],path[i][1]);
                if(i < dp)
                    putchar(',');
                putchar(10);
            }
        }
        if((dp + 1) % 9)
            putchar(10);
        ok = true;
        return;
    }
//    printf("%d  %d\n",curi,curj);
//    printf("%d  %d  %d  %d  %d  %d\n",u,d,f,b,l,r);
//    system("pause");
    if(curi > 1 && (map[curi - 1][curj] == u || map[curi - 1][curj] == -1))
        dfs(curi - 1,curj,dp + 1,f,b,d,u,l,r);
    if(curi < n && (map[curi + 1][curj] == u || map[curi + 1][curj] == -1))
        dfs(curi + 1,curj,dp + 1,b,f,u,d,l,r);
    if(curj > 1 && (map[curi][curj - 1] == u || map[curi][curj - 1] == -1))
        dfs(curi,curj - 1,dp + 1,l,r,f,b,d,u);
    if(curj < m && (map[curi][curj + 1] == u || map[curi][curj + 1] == -1))
        dfs(curi,curj + 1,dp + 1,r,l,f,b,u,d);

    flag[curi][curj][u][f] = 0;
}

int nextint()
{
    char c;
    int ret;
    bool sig = false;
    while(isspace(c = getchar()))
        ;
    if(c == '-')
    {
        sig = true;
        c = getchar();
    }
    ret = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        ret = ret * 10 + c - '0';
    return sig?-ret:ret;
}

int main()
{
    int i,j;
    while(~scanf("%s",s))
    {
        if(strcmp(s,"END") == 0)
            break;
        n = nextint();
        m = nextint();
        si = nextint();
        sj = nextint();
        up = nextint();
        fa = nextint();
        for(i = 1;i <= n;i ++)
            for(j = 1;j <= m;j ++)
                map[i][j] = nextint();
        memset(flag,0,sizeof(flag));
        ok = false;
        printf("%s\n",s);
        for(i = 0;i < 24;i ++)
            if(die[i][0] == up && die[i][2] == fa)
                break;
        //printf("u:%d d:%d f:%d b:%d l:%d r:%d\n",die[i][0],die[i][1],die[i][2],die[i][3],die[i][4],die[i][5]);
        ctrl = 1;
        while(1)
        {
            if(ctrl >= m * n * 6 || ok)
                break;
            dfs(si,sj,0,die[i][0],die[i][1],die[i][2],die[i][3],die[i][4],die[i][5]);
            ctrl ++;
        }
        //printf("%d\n",ctrl);
        if(ok == false)
            printf("  No Solution Possible\n");
    }
    return 0;
}
//156K	47MS

不用迭代加深也能过!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ 1321 排兵布阵问题可以使用 DFS 算法求解。 题目要求在一个 n x n 的棋盘上,放置 k 个棋子,其中每行、每列都最多只能有一个棋子。我们可以使用 DFS 枚举每个棋子的位置,对于每个棋子,尝试将其放置在每一行中未被占用的位置上,直到放置了 k 个棋子。在 DFS 的过程中,需要记录每行和每列是否已经有棋子,以便在尝试放置下一个棋子时进行判断。 以下是基本的 DFS 模板代码: ```python def dfs(row, cnt): global ans if cnt == k: ans += 1 return for i in range(row, n): for j in range(n): if row_used[i] or col_used[j] or board[i][j] == '.': continue row_used[i] = col_used[j] = True dfs(i + 1, cnt + 1) row_used[i] = col_used[j] = False n, k = map(int, input().split()) board = [input() for _ in range(n)] row_used = [False] * n col_used = [False] * n ans = 0 dfs(0, 0) print(ans) ``` 其中,row 代表当前尝试放置棋子的行数,cnt 代表已经放置的棋子数量。row_used 和 col_used 分别表示每行和每列是否已经有棋子,board 则表示棋盘的状态。在尝试放置棋子时,需要排除掉无法放置的位置,即已经有棋子的行和列,以及棋盘上标记为 '.' 的位置。当放置了 k 个棋子时,即可计数一次方案数。注意,在回溯时需要将之前标记为已使用的行和列重新标记为未使用。 需要注意的是,在 Python 中,递归深度的默认限制为 1000,可能无法通过本题。可以通过以下代码来解除限制: ```python import sys sys.setrecursionlimit(100000) ``` 完整代码如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值