UVa 1533:Moving Pegs(迭代加深搜索)

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=842&page=show_problem&problem=4308

分析:如图所示,一共有15个洞,其中一个空着,剩下的洞里各有一个小球。每次可以让一个小球越过同一条直线上的一个或多个连续的小球,落到最近的空洞(不能越过空洞),然后拿走被跳过的小球。例如,让14调到空洞5中,则洞9里的小球会被拿走,因此操作之后洞9和14会变空,而5里面会有一个小球。你的任务是用最少的步数让整个棋盘只剩下一个小球,并且位于初始时的那个空洞中。(本段摘自《算法竞赛入门经典(第2版)》)

分析:
       使用迭代加深搜索,事先在常量数组里存好可以跳的地方和会经过的棋子。处理起来方便一点。

代码:

#include <iostream>
#include <algorithm>
#include <fstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <cctype>
#include <stack>
#include <set>

using namespace std;

const int maxn = 15 + 5, INF = 10;

const int z[16][6] = {
{},
{ 4, 6, 7,10,11,15},
{ 7, 9,11,14},
{ 8,10,12,15},
{ 1, 6,11,13},
{12,14},
{ 1, 4,13,15},
{ 1, 2, 9,10},
{ 3,10},
{ 2, 7},
{ 1, 3, 7, 8},
{ 1, 2, 4, 13,14,15},
{ 3, 5,14,15},
{ 4, 6,11,15},
{ 2, 5,11,12},
{ 1, 3, 6,11,12,13}
};

const int WAY[100][3] = {
{ 1, 4, 2},{ 1, 6, 3},{ 1, 7, 2},{ 1, 7, 4},{ 1,10, 3},{ 1,10, 6},{ 1,11, 2},{ 1,11, 4},{ 1,11, 7},{ 1,15, 3},{ 1,15, 6},{ 1,15,10},
{ 2, 7, 4},{ 2, 9, 5},{ 2,11, 4},{ 2,11, 7},{ 2,14, 5},{ 2,14, 9},
{ 3, 8, 5},{ 3,10, 6},{ 3,12, 5},{ 3,12, 8},{ 3,15, 6},{ 3,15,10},
{ 4, 1, 2},{ 4, 6, 5},{ 4,11, 7},{ 4,13, 8},
{ 5,12, 8},{ 5,14,9},
{ 6, 1, 3},{ 6, 4, 5},{ 6,13, 9},{6, 15,10},
{ 7, 1, 2},{ 7, 1, 4},{ 7, 2, 4},{ 7, 9, 8},{ 7,10, 8},{ 7,10, 9},
{ 8, 3, 5},{ 8,10, 9},
{ 9, 2, 5},{ 9, 7, 8},
{10, 1, 3},{10, 1, 6},{10, 3, 6},{10, 7, 8},{10, 7, 9},{10, 8, 9},
{11, 1, 2},{11, 1, 4},{11, 1, 7},{11, 2, 4},{11, 2, 7},{11, 4, 7},{11,13,12},{11,14,12},{11,14,13},{11,15,12},{11,15,13},{11,15,14},
{12, 3, 5},{12, 3, 8},{12, 5, 8},{12,14,13},{12,15,13},{12,15,14},
{13, 4, 8},{13, 6, 9},{13,11,12},{13,15,14},
{14, 2, 5},{14, 2, 9},{14, 5, 9},{14,11,12},{14,11,13},{14,12,13},
{15, 1, 3},{15, 1, 6},{15, 1,10},{15, 3, 6},{15, 3,10},{15, 6,10},{15,11,12},{15,11,13},{15,11,14},{15,12,13},{15,12,14},{15,13,14}
};

int T, x;
int v[maxn], path[maxn][2];
vector< int > vec[maxn];
vector< int > way[maxn][maxn];

void init()
{
    for (int i = 1; i <= 15; ++i)
    {
        for (int j = 0; j < 6; ++j)
            if (z[i][j])
                vec[i].push_back(z[i][j]);
    }
    for (int i = 0; i < 100; ++i)
        way[WAY[i][0]][WAY[i][1]].push_back(WAY[i][2]);
}

bool judge()
{
    for (int i = 1; i <= 15; ++i)
        if ((i == x && !v[i]) || (i != x && v[i]))
            return false;
    return true;
}

bool jump(int x, int y)
{
    for (int i = 0; i < way[x][y].size(); ++i)
        if (!v[way[x][y][i]])
            return false;
    return true;
}

void remove(int x, int y)
{
    for (int i = 0; i < way[x][y].size(); ++i)
        v[way[x][y][i]] = 0;
    v[x] = 0;
    v[y] = 1;
}

void recover(int x, int y)
{
    for (int i = 0; i < way[x][y].size(); ++i)
        v[way[x][y][i]] = 1;
    v[x] = 1;
    v[y] = 0;
}

bool DFS(int deep, int limit)
{
    if (deep == limit)
    {
        if (judge())
        {
            printf("%d\n", limit);
            for (int i = 0; i < limit; ++i)
                if (i < limit - 1)
                    printf("%d %d ", path[i][0], path[i][1]);
                else
                    printf("%d %d\n", path[i][0], path[i][1]);
            return true;
        }
        return false;
    }
    for (int i = 1; i <= 15; ++i)
    {
        if (v[i])
        {
            for (int j = 0; j < vec[i].size(); ++j)
            {
                int u = vec[i][j];
                if (!v[u] && jump(i, u))
                {
                    remove(i, u);
                    path[deep][0] = i;
                    path[deep][1] = u;
                    if (DFS(deep + 1, limit))
                        return true;
                    recover(i, u);
                }
            }
        }
    }
    return false;
}

int main()
{
    init();
    scanf("%d", &T);
    for (int C = 0; C < T; ++C)
    {
        scanf("%d", &x);
        for (int i = 1; i <= 15; ++i)
            if (i == x)
                v[i] = 0;
            else
                v[i] = 1;
        for (int maxd = 1; ; ++maxd)
            if (DFS(0, maxd))
                break;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值