📜  门| GATE-CS-2015(Set 2)|问题7(1)

📅  最后修改于: 2023-12-03 15:42:17.632000             🧑  作者: Mango

问题描述

给定一个n*n的方格迷宫,每个方格表示一个房间。每个房间有4个门分别通向上下左右四个方向,其中某些门可以通往围墙之外。你可以从某个指定起点出发,尝试访问所有可达房间,然后返回起点。请写一个递归算法来找到此旅程的长度的最小值。

函数原型:int minCost(int points[][n])。

测试输入

输入数据的格式如下:

第一行是整数n(2<=n<=18),表示迷宫的大小。

接下来的n行分别包含n个数字,表示房间的状态。状态为1表示该方格房间有通向上下左右四个方向的门,为0则表示无门、或该方向通向围墙。

最后一行是起点的坐标。

例如:

4
1 1 0 0
0 1 1 0
1 1 1 0
1 1 1 1
0 0
测试输出

输出数据的格式应该如下:

第一行是最小成本。

第二行是遍历的路径。如果有多个,只需选择其中之一。

例如:

7
(0,0)->(0,1)->(1,1)->(1,2)->(2,2)->(2,1)->(3,1)->(3,2)->(2,0)->(1,0)->(0,0)
解题思路

题目可以看作是求一个无向图的哈密顿回路,即从任意一个点出发,沿着图中的边走一次经过每个点且只经过一次,最终回到起点的路径。问题可以转换为寻找从起点出发,穿过所有点的最短路径。可以使用动态规划解决。

我们可以定义状态dp(i, S) 表示从起点0出发,走过集合S (即已经走过的点),最后到达点i的最小代价。其中,集合 S 内的点已经被遍历过,即已经经过“哈密顿回路”的部分路径了。集合 S 的元素全部为首尾两个点,即 S= {0, i}。因为最后需回到起点。

初始状态为dp(i,{0,i})=cost(0,i),其中,cost(x,y) 表示x和y之间的距离(本题中设距离为欧式距离)。

转移方程为:

  • 若集合S中元素个数≥2,状态转移方程为

    dp(i,S)=min{dp(j,S-{i})+cost(j,i)},其中j∈S,且j≠i

  • 若集合S中仅有一个元素,有

    dp(i,{0})=cost(0,i)

所以,状态转移方程为:

dp(i, S) = min(dp(j, S-{i}) + cost(j, i)), j∈S 且 j≠i
dp(i, {0}) = cost(0, i)
动态规划解法
const int MAXN = 18;

int cost[MAXN][MAXN];
int dp[1 << MAXN][MAXN];
int num_points;

int minCost(int points[][MAXN])
{
    num_points = 0;
    for (int i = 0; i < MAXN * MAXN; i++)
    {
        int x = i / MAXN, y = i % MAXN;
        if (points[x][y])
        {
            for (int dx = -1; dx <= 1; dx++)
            {
                for (int dy = -1; dy <= 1; dy++)
                {
                    if (dx * dx + dy * dy == 1)
                    {
                        int nx = x + dx, ny = y + dy;
                        if (nx >= 0 && nx < MAXN && ny >= 0 && ny < MAXN && points[nx][ny])
                        {
                            cost[i][nx * MAXN + ny] = cost[nx * MAXN + ny][i] = abs(x - nx) + abs(y - ny);
                        }
                    }
                }
            }
            num_points++;
        }
    }

    memset(dp, -1, sizeof(dp));
    for (int i = 0; i < MAXN; i++)
    {
        dp[1<<i][i] = cost[0][i*MAXN];
    }

    for (int s = 0; s < (1<<num_points); s++)
    {
        for (int i = 0; i < num_points; i++)
        {
            if (!(s & (1<<i))) continue;
            for (int j = 0; j < num_points; j++)
            {
                if (i == j || !(s & (1<<j))) continue;
                int state = s & ~(1<<i);
                if (dp[state][j] < 0) continue;
                if (dp[s][i] < 0 || dp[s][i] > dp[state][j] + cost[j*MAXN+i])
                {
                    dp[s][i] = dp[state][j] + cost[j*MAXN+i];
                }
            }
        }
    }
    return dp[(1<<num_points)-1][0];
}
参考文献
  1. 最优哈密顿回路
  2. GATE-CS-2015(Set 2)| 问题7