zoukankan      html  css  js  c++  java
  • [USACO3.2]魔板 Magic Squares

    松下问童子,言师采药去。
    只在此山中,云深不知处。——贾岛

    题目:魔板 Magic Squares

    网址:https://www.luogu.com.cn/problem/P2730

    这是一张有8个大小相同的格子的魔板:

    1 2 3 4

    8 7 6 5

    题目描述

    我们知道魔板的每一个方格都有一种颜色。这8种颜色用前8个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。

    对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示。
    这是基本状态。

    这里提供三种基本操作,分别用大写字母“A”,“B”,“C”来表示(可以通过这些操作改变魔板的状态):

    “A”:交换上下两行;

    “B”:将最右边的一列插入最左边;

    “C”:魔板中央四格作顺时针旋转。

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

    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

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

    你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。

    输入格式

    只有一行,包括8个整数,用空格分开(这些整数在范围 1——8 之间)不换行,表示目标状态。

    输出格式

    Line 1: 包括一个整数,表示最短操作序列的长度。

    Line 2: 在字典序中最早出现的操作序列,用字符串表示,除最后一行外,每行输出60个字符。

    输入样例
    2 6 8 4 5 7 3 1 
    
    输出样例
    7 
    BCABCCB
    
    说明

    选自USACO Training Section 3.2

    做完八数码问题,不难理解这道题可以使用广搜解决(毕竟时间复杂度与八数码问题类似)。

    像之前的八数码问题一样,我们把状态定义成一个八位数,代码中简单的使用STL中map和set进行记录与判重。

    留意:本题有一个陷肼,如果使用从上到下、从左向右进行加和操作确定状态时,初状态应为:12348765!

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    const int rot[4] = {2, 1, 5, 6};
    int st = 12348765, ed = 0, s[10];
    map <int, int> d, f;
    set <int> vis;
    void decode(int state, int *p)
    {
    	for(int i = 7; i >= 0; -- i)
    	{
    		p[i] = state % 10;
    		state /= 10;
    	}
    	//将十进制编码转化为数组
    	return;
    }
    int encode(int *p)
    {
    	int cnt = 0;
    	for(int i = 0; i < 8; ++ i)
    	{
    		cnt = (cnt << 1) + (cnt << 3) + p[i];
    	}
    	//将数组转化为十进制8位编码
    	return cnt;
    }
    void flip(int cur, int *p)
    {
    	switch(cur)
    	{
    		case 0 :
    		{
    			for(int i = 0; i < 4; ++ i)
    			{
    				swap(p[i], p[i + 4]);
    			}
    			break;
    		}
    		case 1 :
    		{
    			for(int i = 2; i > -1; -- i)
    			{
    				swap(p[i], p[i + 1]);
    				swap(p[i + 4], p[i + 5]);
    			}
    			break;
    		}
    		case 2 :
    		{
    			for(int i = 0; i < 3; ++ i)
    			{
    				swap(p[rot[i]], p[rot[i + 1]]);
    			}
    			break;
    		}
    	}
    	return;
    }
    void print_ans(int state)
    {
    	if(state == st) return;
    	int prev_state = 0;
    	decode(state, s);
    	switch(f[state])
    	{
    		case 0:
    		{
    			for(int i = 0; i < 4; ++ i)
    			{
    				swap(s[i], s[i + 4]);
                }
    			break;
    		}
    		case 1:
    		{
    			for(int i = 0; i < 3; ++ i)
    			{
    				swap(s[i], s[i + 1]);
    				swap(s[i + 4], s[i + 5]);
    			}
    			break;
    		}
    		case 2:
    		{
    			for(int i = 2; i >= 0; -- i)
    			{
    				swap(s[rot[i + 1]], s[rot[i]]);
                }
    			break;
    		}
    	}
    	for(int i = 0; i < 8; ++ i)
    	{
    		prev_state = prev_state * 10 + s[i];
    	}
    	memset(s, 0, sizeof(s));
    	print_ans(prev_state);
    	printf("%c", f[state] + 'A');
    	return;
    }
    void bfs()
    {
        //特判 初始状态 和 目标状态 相同
        if(st == ed) {
            puts("0");
            return;
        }
        
    	f.clear(), vis.clear();
    	queue <int> Q;
    	while(!Q.empty()) Q.pop();
    	
    	Q.push(st);
    	vis.insert(st);
    	int copy[8] = {}, now, next;
    	
    	while(!Q.empty())
    	{
    		now = Q.front();
    		Q.pop();
    		decode(now, s);
    		memcpy(copy, s, sizeof(copy));
    		for(int i = 0; i < 3; ++ i)
    		{
    			flip(i, s);
    			next = encode(s);
    			memcpy(s, copy, sizeof(s));
    
    			if(vis.count(next)) continue;
    			d[next] = d[now] + 1;
    			f[next] = i;
    			if(next == ed)
    			{
    				printf("%d
    ", d[next]);
    				print_ans(next);
    				return;
    			}
    			Q.push(next);
    			vis.insert(next);
    		}
    	}
    	return;
    }
    int main()
    {
    	memset(s, 0, sizeof(s));
    	for(int i = 0; i < 4; ++ i) scanf("%d", &s[i]);
    	//目标状态处理:
    	for(int i = 7; i >= 4; -- i) scanf("%d", &s[i]);
    	//留意陷阱呢
    	for(int i = 0; i < 8; ++ i)
    	{
    		ed = (ed << 1) + (ed << 3) + s[i];
    	}
        bfs();
    	return 0;
    }
    
  • 相关阅读:
    神器Tampermonkey的安装使用
    记一些不错的知识博客
    redis入门到精通系列(九):redis哨兵模式详解
    redis入门到精通系列(八):redis的高可用--主从复制详解
    redis入门到精通系列(七):redis高级数据类型详解(BitMaps,HyperLogLog,GEO)
    redis入门到精通系列(六):redis的事务详解
    redis入门到精通系列(五):redis的持久化操作(RDB、AOF)
    redis入门到精通系列(四):Jedis--使用java操作redis详解
    jsp乱码
    Tomcat 9遇到错误开着怎么关闭
  • 原文地址:https://www.cnblogs.com/zach20040914/p/12764320.html
Copyright © 2011-2022 走看看