首页 > 其他分享 >「USACO3.2」Magic Squarest题解

「USACO3.2」Magic Squarest题解

时间:2023-08-30 09:46:15浏览次数:47  
标签:10 题目 Squarest 题解 int USACO3.2 操作

「USACO3.2」Magic Squarest题解


建议优先阅读题目后再看题解:
FZQOJ
luogu

-题目大意

给定初始二维数组(也即是题中所说的魔板):

1 2 3 4

8 7 6 5

并提供以下3种操作:

\(A\).交换上下两行;

\(B\).将最右边的一行移动到最左边;

\(C\).顺时针旋转魔板的中央4个数字

询问最少多少次操作后,可以转换得到题目要求的序列,并输出字典序最小的操作


-思路

首先,因为这道题并没有一个很清晰的转换方向,所以我们采用bfs来记录当前的状态.

struct node{
	int s[10]/*当前的状态*/, val/*当前转换次数*/;
	string ans/*当前进行的操作*/;
};

那么,对于每一种操作,我们只需要模拟即可。因为题目要求字典序最小,我们使用bfs要满足第一次搜到的就最小,那么必须是以\(A\)、\(B\)、\(C\)的顺序模拟。

需要注意的是,因为初始的序列是二维,最后求的序列是一维,所以我们可以将二维改成一维方便模拟

也就是:

{1, 2, 3, 4, 5, 6, 7, 8}

而不是:

{1, 2, 3, 4, 8, 7, 6, 5}

对于操作\(A\), 我们可以:

for(int i = 1, l = 8; i <= 4; i++, l--) swap(w.s[i], w.s[l]);
/*模拟交换上下两行的数字*/

对于操作\(B\), 我们也可以:

int a = w.s[4], b = w.s[5];/*提取出最右边两行的数字*/
w.s[1] = a;/*将第一排最后一个数放到第一位*/
for(int i = 2; i <= 4; i++) w.s[i] = nex.s[i - 1];/*补齐第一排*/
for(int i = 6; i <= 8; i++) w.s[i - 1] = nex.s[i];/*补齐第二排*/
w.s[8] = b;/*将第二排最后一个数放到第一位*/

对于操作\(C\), 我们还可以:

swap(w.s[3], w.s[6]), swap(w.s[3], w.s[7]), swap(w.s[2], w.s[3]);

这是什么意思呢? 让我们来模拟一下:

1

这样就实现了逆时针旋转的效果


最后为了防止重复操作,我们需要判重。

因为一共只有\(8\)个数字,那么只用开\(7\)维数组就够了,因为最后一维一定是固定的。

-\(Code\)(无坑)

#include<bits/stdc++.h>
using namespace std;

struct node{
	int s[10], val;
	string ans;
}g;/*结构体记录状态*/

int k[10] = {0}/*题目要求的结构*/, vis[10][10][10][10][10][10][10] = {0}/*7维判重数组*/, first[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8}/*初始值*/;
queue<node>p;

inline void check(node w, char ch){
	if(!vis[w.s[1]][w.s[2]][w.s[3]][w.s[4]][w.s[5]][w.s[6]][w.s[7]]){
		w.ans += ch, w.val++, vis[w.s[1]][w.s[2]][w.s[3]][w.s[4]][w.s[5]][w.s[6]][w.s[7]] = 1;
		p.push(w);
	}
	return;
}/*判重*/

int main(){ 
	for(int i = 1; i <= 8; i++){
		scanf("%d", &k[i]);
		g.s[i] = first[i];
	}
	g.val = 0;
	p.push(g);/*初始化*/
	while(!p.empty()){
		node nex = p.front();
		p.pop();
		int flag = 1;
		for(int i = 1; i <= 8; i++){
			if(k[i] != nex.s[i]){
				flag = 0;
				break;
			}
		}
		if(flag){/*判断是否找到结果*/
			cout << nex.val << " " << nex.ans;
            /*找到即输出*/
			break;
		}
		/*A操作*/
		flag = 1;
		node w = nex;
		for(int i = 1, l = 8; i <= 4; i++, l--) swap(w.s[i], w.s[l]);
		check(w, 'A');
		/*B操作*/
		w = nex;
		int a = w.s[4], b = w.s[5];
		w.s[1] = a;
		for(int i = 2; i <= 4; i++) w.s[i] = nex.s[i - 1];
		for(int i = 6; i <= 8; i++) w.s[i - 1] = nex.s[i];
		w.s[8] = b;
		check(w, 'B');
		/*c操作*/
		w = nex;
		swap(w.s[3], w.s[6]), swap(w.s[3], w.s[7]), swap(w.s[2], w.s[3]);
		check(w, 'C');
	}
	return 0;
}

最终程序仅用时\(10ms\)!可喜可贺!

都看到这了,点个赞呗!谢谢!

标签:10,题目,Squarest,题解,int,USACO3.2,操作
From: https://www.cnblogs.com/koukilee/p/17666428.html

相关文章

  • [USACO05DEC] Layout G 题解
    fzqojluogu题意分别给出\(ml\)和\(md\)对,关于n头奶牛位置的关系,求1号到n号奶牛的最大距离是多少每一对ml的关系转化成不等式就是:\(A-B\leC\)相应的,每一对md的关系转化成不等式就是:\(A-B\geqC\)(\(A\),\(B\)是两头奶牛的位置,\(C\)是他们相差的距离)思路看到多元的......
  • CF1864D Matrix Cascade 题解
    首先把式子拆一下,可以知道\(x-i\ge|y-j|\)等价于\(x-y\gei-j\)和\(x+y\gei+j\),注意到每次操作\((i,j)\),影响到的点\((x,y)\)均要满足\(x>i\),那么我们每次就必须要按照从上往下的顺序进行,否则上面的点无法影响到,即从第一行开始操作。又注意到对于\((i,j)\)如果执......
  • CF1864B Swap and Reverse 题解
    注意到交换操作,无法改变下标的奇偶性,因此只能通过考虑翻转操作改变。注意到如果\(i\)是奇数,那么要令\(i+k-1\)为偶数的话\(k\)必须为偶数,若\(i\)是偶数,要令\(i+k-1\)是奇数的话,\(k\)也应为偶数,而\(k\)为奇数的情况翻转了也无法改变奇偶性。因此通过\(k\)的奇偶性......
  • CF1839C Insert Zero and Invert Prefix 题解
    首先考虑无解的情况,很明显\(a_n\)必须为\(0\),否则没有解,因为如果最后一位为\(1\)那么必须有\(n\)这个数存在于\(b\)序列中,而这种情况时不符合题意的。然后考虑如何求解,先考虑一种比较特殊的情况,就是若干个\(1\)后面接着一个\(0\),这里假设\(1\)的数量有\(k\)个,这......
  • P9437 『XYGOI round1』一棵树 题解
    首先这是一道很明显的换根dp。首先注意到要拼接数,所以我们可以先处理出\(num_i=10^{x}\),使得\(10^x>a_i>10^{x-1}\),这样方便我们后面算贡献。我们以这棵树为例子来推状态转移方程。先假设\(dp_u\)表示以\(1\)为根时,从\(u\)的子树的点到\(u\)的权值和。那么\[......
  • CF1862E Kolya and Movie Theatre 题解
    先注意到我们娱乐值损耗的多少只与最后一场电影有关系,所以假设最后一场电影看的下标为\(k\),那么最后就要减去\(d\timesk\)。得出这个性质之后开个小根堆反悔贪心即可,首先\(a_i<0\)的没必要考虑,对于\(a_i>0\)的,如果还没到\(m\)场电影,我们就直接往里塞就可以,如果到了,我们......
  • P8675 [蓝桥杯 2018 国 B] 搭积木 题解
    总述此题用区间dp解决,二维前缀和优化。朴素做法阶段:自上而下数每一层。状态:\(dp_{i,l,r}\)表示自上而下数第\(i\)行中在\([l,r]\)摆积木的方案数。状态转移方程:根据题意可知,若要在\([l,r]\)中摆积木,那么\([l,r]\)中不允许有\(\tt{X}\),而第\(i\)层的\([l,r]\)......
  • P7809 [JRKSJ R2] 01 序列 题解
    对于第二种操作,很容易想到只有\(1\)或\(2\)两种答案,若该区间内存在\(01\)这个子序列,那么答案为\(2\)反之为\(1\).可以通过对该\(01\)串做一个前缀和,若出现\(01\)这个子序列就累加,最后判断左右端点是否相等即可,时间复杂度\(O(n)\).对于第一种操作,\(\text{Subtest1}......
  • CF1833D Flipper 题解
    赛场上思路出来了但是代码没调出来。首先考虑右端点,很明显,要让操作后的序列字典序尽量地大,那么就要使操作后的序列第一个数尽量地大,考虑\(n\)或\(n-1\),如果\(n\)在原序列的第一个位置,那么此时无论怎么调整都无法使得它在新序列的第一个位置,此时就要考虑让\(n-1\)在新序列......
  • UVA10054 The Necklace题解
    题意给定一个无向图,其中至多有\(50\)个结点,求是否有欧拉回路。题解很明显就是一个无向图求欧拉回路的板子,我们用\(\tt{Hierholzer}\),先说存图,要明确的一个点是这个无向图里是有可能有重边的,所以我们要注意记录的时候不应是单独地记录某一条边是否存在,而是要记录某一条边的数......