GHOJ 327 漫游小镇

题目描述

        一个正方形的镇区分为N×N个小方块(1≤N≤7)。农场位于方格的左上角,集市位于左下角。奶牛Bessie穿过小镇。从左上角走到左下角,每次可以走上,下,左,右,但不能走出方格的外面,每个格经过且仅经过一次。当N=3时,贝茜的漫游路径可能如下图所示:

Failed to load picture

           写一个程序,对于给出的N值,计算Bessie从农场走到集市有多少条路径。

输入格式

           一行,一个整数N。(1≤N≤7)

输出格式

        只有一行。输出一个整数表示路径的数量。

 

输入样例

2

输出样例

1

 

题解

        明显求哈密顿路径,不知道图论里有没有能快速切这题的算法。(话说还在网上看到了基于cdq论文的题解,学不来,弃了)

        搞不了图论就dfs加剪枝吧。综合众多题解总结了2个剪枝优化。

        剪枝1:

        找当前点的必经点。

        容易想到,如果相邻点的出度为1,那么这个点就是必经点。如果有多个必经点,那就可以想到无论怎么走都走不出哈密顿路径,回溯即可;如果没有必经点,把相邻点都搜一遍即可。

        注意,终点判断必经点是判断出度是否为0(自己思考为什么)。

        剪枝2:

        找当前点的必不经点。

        这个有点难想。我们可以思考,如果走了一个点,把整张图分成若干个部分,那么显然遍历不了整张图。

        这里为了防止剪枝负优化,只采用了判断是否会分成两个部分的剪枝。

        如果当前点的相邻点出度为2,且出点在同行或同列,那就可以想到走这个点必定将图分成两个部分,直接跳过即可。

        综上,一个时间复杂度十分低的程序就出来了。但事实上,本人还是认为这题有更多的剪枝方案。先放着,留到以后再想。

#include <iostream>

using namespace std;

const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
int n, lim;
int out[10][10];
bool f[10][10];
int ans;

void DFS(int x, int y, int dep)
{
    if(x == n && y == 1)
    {
        if(dep == lim) ++ans;
        return;
    }
    f[x][y] = 1;
    int cnt = 0, p;
    for(register int i = 0; i < 4; ++i)
    {
        --out[x + dx[i]][y + dy[i]];
    }
    int tx, ty;
    for(register int i = 0; i < 4; ++i)
    {
        tx = x + dx[i];
        ty = y + dy[i];
        if(f[tx][ty]) continue;
        if(tx != n || ty != 1)
        {
            if(out[tx][ty] == 1) ++cnt, p = i;
        }
        else
        {
            if(!out[tx][ty]) ++cnt, p = i;
        }
    }
    if(cnt == 1) DFS(x + dx[p], y + dy[p], dep + 1);
    else if(!cnt)
    {
        for(register int i = 0; i < 4; ++i)
        {
            tx = x + dx[i];
            ty = y + dy[i];
            if(f[tx][ty]) continue;
            if(out[tx][ty] == 2)
            {
                if(f[tx - 1][ty] && f[tx + 1][ty] && (f[tx][ty - 1] ^ 1) && (f[tx][ty + 1] ^ 1)) continue;
                if((f[tx - 1][ty] ^ 1) && (f[tx + 1][ty] ^ 1) && f[tx][ty - 1] && f[tx][ty + 1]) continue;
            }
            DFS(tx, ty, dep + 1);
        }
    }
    for(register int i = 0; i < 4; ++i)
    {
        ++out[x + dx[i]][y + dy[i]];
    }
    f[x][y] = 0;
    return;
}

int main()
{
    cin >> n;
    lim = n * n;
    for(register int i = 0; i <= n + 1; ++i)
    {
        f[0][i] = f[n + 1][i] = f[i][0] = f[i][n + 1] = 1;
    }
    for(register int i = 1; i <= n; ++i)
    {
        for(register int j = 1; j <= n; ++j)
        {
            out[i][j] = 4;
            if(i == 1 || i == n) --out[i][j];
            if(j == 1 || j == n) --out[i][j];
        }
    }
    DFS(1, 1, 1);
    cout << ans;
    return 0;
}
参考程序
原文地址:https://www.cnblogs.com/kcn999/p/10778168.html