最新文章

这里会显示最新的几篇文章摘要。

再破难关(BFS)

问题 F: 再破难关

题目描述

OIBH组织派出的黄金十二人+青铜五小强还没有到, 他们只能指望原先的机关能够阻拦住柯南的脚步。柯南打开大门之后发现里面还有一个门, 门上还有一个神奇的锁(-,-)
这是一个4*4的锁, 上面有8个凸起的格子和8个被按下的格子,当且仅当两个格子有公共边时, 则称这两个格子是相邻的。

每次操作只能够交换相邻的两个格子,柯南看到了初始锁的状态和目标锁的状态,同样组织只允许他用最少步数打开锁。

输入

第1到4行每行四个数字(1或者0),描述了初始锁状态。
接着是一个空行
第6到9行每行四个数字,描述了最终锁状态。

输出

输出只有一行,是一个整数n,表示最少的操作次数。

样例输入

1111
0000
1110
0010 

1010
0101
1010
0101

样例输出

4

分析

这道题题意就是在最短的交换次数从原图转换为目标图
这可以看作是图,每个状态为节点,一次操作作为从当前状态到新状态的边,但我不是很能理解,可能最后像树一样,树的高度就是最少操作数
这道题的核心是使用BFS实现合法的交换,对新状态再进行BFS合法交换,每次只能和相邻的点交换,那么从一个状态可以走出4种状态,一直进行下去相当于一棵4叉数,实现遍历所有情况,其中对已经实现过的情况进行剪枝
逐步实现:

  1. 怎么储存状态?把4x4的表格二维图转化为一维的字符串相当于把v[i][j]映射到s[i*4+j]
  2. 剪枝和记录状态,使用哈希表就可以了
  3. BFS的实现,当然用是queue
  4. 由于交换操作要求相邻格子才能交换,意味着在一个状态中,选定一对相邻格子,如果一个是 1、另一个是 0,则交换后形成新的状态。

代码细节


signed main() {
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);

    string orgsta = "",ditsta = "";  //初始状态和目标状态
    for (int i = 0;i < 4;++i)
        for (int j = 0;j < 4;j++) {
            char t;
            cin >> t;               //先读入为int的话因为没有空格,一行会被当作一个数读入
            orgsta += t;
        }
    //cout << orgsta;


    for (int i = 0;i < 4;++i)
        for (int j = 0;j < 4;j++) {
            char t;
            cin >> t;
            ditsta += t;
        }

    if (orgsta == ditsta) {      //初状态等于目标状态
        cout << 0;
        return 0;
    }

    queue<string> q;
    unordered_map<string,int> mp;  //标记状态,顺便记录操作次数
    q.push(orgsta);
    mp[orgsta] = 0;

    int tx[4]{0,1,0,-1};
    int ty[4]{1,0,-1,0};

    while (!q.empty()) {
        string cur = q.front();
        q.pop();
        for (int i = 0;i < 16;++i) {       //对每一个进行一次BFS
            int x  = i/4, y = i % 4;       //还原坐标
            for (int j = 0; j <  4;++j) {
                int nx = x + tx[j],ny = ty[j] + y;
                if (nx >= 0 && nx < 4 && ny >= 0 && ny < 4 && cur[i] != cur[nx*4+ny]) {  //满足交换条件
                    string now = cur;    
                    swap(now[i] , now[nx*4+ny]);
                    if (!mp.count(now)) {         //这里使用count检查key,直接使用mp[now]==0,的话,如果回到初始状态,那么初始状态恰好等于0,可能会错
                        mp[now] = mp[cur] + 1;
                        if (now == ditsta) {
                            cout << mp[now];
                            return 0;
                        }
                        q.push(now);             
                    }
                }
            }

        }
    }
    return 0;
}
posted @ 2025-03-16 00:12  bakul  阅读(22)  评论(0)    收藏  举报