• 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;
    }
    参考程序
  • 相关阅读:
    SpringMVC项目模块浅析
    利用python脚本(xpath)抓取数据
    利用python脚本(re)抓取美空mm图片
    Intellij idea开发Hadoop MapReduce程序
    在Hadoop平台跑python脚本
    Hadoop常用命令
    CentOS6.5 安装Zookeeper集群
    MySQL常用命令
    MongoDB常用命令
    前后端分离架构+k8s+ingress
  • 原文地址:https://www.cnblogs.com/kcn999/p/10778168.html
Copyright © 2020-2023  润新知