杭电1195 搜索

杭电1195

原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=1195
题意: 有一个密码锁,给定了当前状态和正确的状态。求到达目的状态所需的最小步数。每一步只能这样做:对某位数加1,对某位数减1,交换相邻两数的位置。

思路:

之前做的都是在矩阵上进行BFS,这次突然转成这样了都不会做了。但其实思路还都是一样的。

原来的矩阵,搜索时要往四个方向找,现在需要往11个方向搜索,这就是“状态转移”的不同的地方。
原来矩阵的每个元素作为一个node,需要给定元素的坐标和当前step。在这里需要给定当前的状态,也就是由原来的两个变量定位该node变成了四个变量定位该node。
原来的visited数组存储每个坐标的元素有没有被访问过,所以这次变成了四维数组。
还有一点需要注意的是,和原来一样,这次我用一个数组dis存储原状态到每个状态的step,最后再直接从dis数组中直接拿到答案。还可以用另一种方法,就是当判断到状态转移之后的node是目的状态时,直接退出循环,将当前的step输出即可。

下面是AC代码:

//#include "stdafx.h"
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <queue>
#include "stdio.h"
using namespace std;

int a[4], b[4];
int visited[10][10][10][10];
int dis[10000];//四位密码最多有10000个状态,这里存储到每个状态的step
//其实,这里也可以在next那里直接判断,看是不是目标状态,如果到达目标状态,就直接退出循环。
//int ans; //用另外一种方法(找到目标状态直接返回,就存储到一个ans中即可
struct node {
    int num[4];//这个数组存储的是密码锁四位状态
    int step; //每个节点都记录一下当前步数
    node() {}
    node(int n1, int n2, int n3, int n4, int step1) {
        num[0] = n1, num[1] = n2, num[2] = n3, num[3] = n4, step = step1;
    }
};
node change(node t, int i) {
    node retur = t;
    if(i < 4){//+
        if (retur.num[i] == 9) retur.num[i] = 1;//注意一下题目要求9加1变成1
        else
            retur.num[i]++;
    }
    else if (i < 8) { //-
        if (retur.num[i % 4] == 1) retur.num[i % 4] = 9;
        else
            retur.num[i % 4]--;
    }
    else { //交换
        int temp = retur.num[i % 4];
        retur.num[i % 4] = retur.num[i % 4 + 1];
        retur.num[i % 4 + 1] = temp;
    }
    return retur;
}
void bfs(node nod) {
    queue<node> q;
    q.push(nod);
    while (!q.empty()) {
        node now = q.front();
        q.pop();

        //如果用另外一种方法,找到目的状态之后就退出也可以
        /*if (now.num[0] == b[0] && now.num[1] == b[1] && now.num[2] == b[2] && now.num[3] == b[3]) {
            ans = now.step;
            return;
        }*/

        for (int i = 0; i < 11; i++) {//每次一共有11种变换形式
            node next = change(now, i); //因为11种形式中,每个都不同,要进行加减1或者交换操作,所以专门写一个函数
            if (visited[next.num[0]][next.num[1]][next.num[2]][next.num[3]] == 0) {
                visited[next.num[0]][next.num[1]][next.num[2]][next.num[3]] = 1;
                next.step = now.step + 1;
                q.push(next);
                dis[next.num[0] * 1000 + next.num[1] * 100 + next.num[2] * 10 + next.num[3]] = next.step;               
            }
        }
    }

}
int main() {
    int t;
    cin >> t;
    while (t--) {
        int tempa, tempb; //要注意,读入一个int型,然后再分到数组中
        cin >> tempa >> tempb;
        for (int i = 0; i < 4; i++) {
            a[3 - i] = tempa % 10;
            tempa /= 10;
            b[3 - i] = tempb % 10;
            tempb /= 10;
        }
        memset(visited, 0, sizeof(visited));
        node start(a[0], a[1], a[2], a[3], 0);
        //与原来的矩阵搜索不一样,这个一共有11种操作,而之前的矩阵是上下左右四种操作。
        //还有一个不一样的地方是,矩阵的每个元素作为一个node,该结构体中有两个坐标和一个step
        //但是这个每个node作为一种状态,是有四个元素的状态和一个step。
        bfs(start);
        int ans = b[0] * 1000 + b[1] * 100 + b[2] * 10 + b[3]; //所有状态都bfs一遍之后,dis也就存储完了,然后直接从dis数组中拿目标状态的step就可以了。
        ans = dis[ans];
        cout << ans << endl;
    }
}
发布了56 篇原创文章 · 获赞 49 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/IBelieve2016/article/details/75647590