魔板 usaco,信息学奥赛一本通

题面

给定一个矩阵

1 2 3 4
8 7 6 5

我们用1 2 3 4 5 6 7 8表示这个矩阵

有三个操作

A:交换上下两行;
B:将最右边的一列插入到最左边;
C:魔板*对的4个数作顺时针旋转。

下面是对基本状态进行操作的示范:

A:

8 7 6 5
1 2 3 4

B:

4 1 2 3
5 8 7 6

C:

1 7 2 4
8 6 3 5

对于每种可能的状态,这三种基本操作都可以使用。

要求求出从12345678到目标状态的最小操作数,并且输出字典序最小的答案

输入样例:

2 6 8 4 5 7 3 1

输出样例:

7
BCABCCB

思路

这是一道比较有趣的搜索题,我们主要思路就是用起始状态进行BFS,每次求出三个状态,以ABC的顺序进行BFS

每个状态记录其前驱状态及其操作的字符

并且转移我们的操作数(前驱状态操作数+1)

这两点都用map来实现就很方便

其他就没有太多的难点,这题主要难在代码量比较大,属于模拟+搜索,码农题

代码

#include<bits/stdc++.h>
using namespace std;
unordered_map<string,int> dis;
unordered_map<string,pair<char,string> > pre;
string move1(string t)
{
    string res="";
    for(int i=7;i>=4;i--) res+=t[i];
    for(int i=3;i>=0;i--) res+=t[i];
    return res;
}
string move2(string t)
{
    string res="";
    res+=t[3];
    for(int i=0;i<3;i++) res+=t[i];
    for(int i=5;i<8;i++) res+=t[i];
    res+=t[4];
    return res;
}
string move3(string t)
{
    string res=t;
    swap(res[5],res[6]);
    swap(res[1],res[2]);
    swap(res[1],res[5]);
    return res;
}
int bfs(string start,string end)
{
    if (start==end) return 0;
    queue<string> q;
    q.push(start);
    dis[start]=0;
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        string str[3];
        //计算出三种目标状态的字符串,顺序必须是ABC
        str[0]=move1(t);
        str[1]=move2(t);
        str[2]=move3(t);
        for(int i=0;i<3;i++)
        {
            if (dis.count(str[i])==0)//没有在dis里出现过就代表是合法的
            {
                dis[str[i]]=dis[t]+1;
                pre[str[i]]={char(i+‘A‘),t};
                if (str[i]==end) return dis[str[i]];
                q.push(str[i]);

            }
        }
    }
}
int main(){
    string start="12345678",end="";//初始状态为1234578
    for(int i=0;i<8;i++)
    {
        int x;
        cin>>x;
        end+=char(‘0‘+x);//处理字符
    }
    int step=bfs(start,end);//bfs
    cout<<step<<endl;
    string res="";
    while(end!=start)//因为记录的是前驱,所以要如同并查集一样
    {
        res+=pre[end].first;
        end=pre[end].second;
    }
    reverse(res.begin(),res.end());//答案是倒着的,要reverse
    if (step>0) cout<<res<<endl; 
    return 0;
}

魔板 usaco,信息学奥赛一本通

上一篇:2021CCPC网络选拔赛


下一篇:浅析flex布局被子元素内容撑破的问题 - Flex布局中一个不为人知的特性(flex-item项目的最小尺寸问题)