九连环

目录

一,九连环

二,九连环所有步骤

三,OJ实战

力扣 1611. 使整数变为 0 的最少操作次数

POJ 1832 连环锁(九连环的推广)


一,九连环

许多人一定很熟悉九连环(如下图)

九个环被串在一起,操作规则如下:第一个(右边)环可以任意装卸,如果第k个环没有被卸掉,而第k个环前边(右边)的所有环都被卸掉,则第k+1个环(第k个环左边的环)可以任意装卸(如果存在的话)。 
用0表示此换被卸掉,1表示此环没有被卸掉,则九连环的每个状态可以用一个长度为9的二进制串来表示,如:111111001经过一次操作可以变成111111000,也可以变成111111011,111111111经过一次操作可以变成111111110,也可以变成111111101。 

这是我八分钟盲拧九连环的视频:

资源分享汇总_nameofcsdn的博客-CSDN博客

二,九连环所有步骤

九连环就是典型的递归

只需要up和down2个函数互相调用即可

对于初始状态111111111,要变成000000000,需要在main函数里面调用9次down函数

代码:

#include<iostream>
using namespace std;

int l[10];

void down(int n);
void up(int n)
{
	if (l[n])return;
	up(n - 1);
	for (int i = n - 2; i > 0; i--)down(i);
	cout << "上" << n << "     ";
	l[n] = 1;
}
void down(int n)
{
	if (n*l[n] == 0)return;
	up(n - 1);
	for (int i = n - 2; i > 0; i--)down(i);
	cout << "下" << n << "     ";
	l[n] = 0;
}

int main()
{
	for (int i = 0; i < 10; i++)l[i] = 1;
	for (int i = 9; i>0; i--)down(i);
	return 0;
}

结果:

下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下7     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下9     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上7     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下8     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下7     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1

一共341步

但是,玩过九连环的朋友都知道,从状态*11变成*00,或者从状态*00变成*11,只需要1步

也就是说,最右边的2个环可以一起装卸

这样,我们就需要调整输出了。

仔细说来,我们的目标是把所有的“下2     下1”换成“下21”,把所有的“上1     上2”换成“上12”

可以通过修改递归终止条件来实现,也可以把输出的结果入栈(或队列),在出栈(或队列)的时候进行合并,还可以直接把输出结果当成一个字符串,然后查找关键词替换。

查找关键词替换可以通过编程实现,也可以直接用word

总之结果如下:

下1 下3 上1 下21 下5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 下7 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 上5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 下6 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 下5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 下9 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 上5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 上6 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 下5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 上7 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 上5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 下6 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 下5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 下8 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 上5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 上6 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 下5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 下7 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 上5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21 下6 上12 下1 上3 上1 下21 上4 上12 下1 下3 上1 下21 下5 上12 下1 上3 上1 下21 下4 上12 下1 下3 上1 下21

刚好256步,256的2的8次方

实际上,无论是简化之前的341步,还是简化之后的256步,都满足f(n)=f(n-1)+2f(n-2)+1(这个递推式是比较显然的)

只不过简化之前的初始值是f(2)=2,f(3)=5,而简化之后的初始值是f(2)=1,f(3)=4

上面的2阶常系数齐次线性递推式还可以转化成1阶常系数齐次线性递推式。

对于状态000000000,要变成111111111,需要在main函数里面调用9次up函数

只需要修改main函数即可

代码:

int main()
{
	for (int i = 0; i < 10; i++)l[i] =(i==0);
	for (int i = 9; i>0; i--)up(i);
	return 0;
}

结果:

上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上7     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上8     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下7     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     下6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上9     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上6     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     下5     上1     上2     下1     上3     上1     下2     下1     下4     上1     上2     下1     下3     上1     下2     下1     上7     上1     上2     下1     上3     上1     下2     下1     上4     上1     上2     下1     下3     上1     下2     下1     上5     上1     上2     下1     上3     上1

三,OJ实战

力扣 1611. 使整数变为 0 的最少操作次数

给你一个整数 n,你需要重复执行多次下述操作将其转换为 0 :

  • 翻转 n 的二进制表示中最右侧位(第 0 位)。
  • 如果第 (i-1) 位为 1 且从第 (i-2) 位到第 0 位都为 0,则翻转 n 的二进制表示中的第 i 位。

返回将 n 转换为 0 的最小操作次数。

示例 1:

输入:n = 3
输出:2
解释:3 的二进制表示为 "11"
"11" -> "01" ,执行的是第 2 种操作,因为第 0 位为 1 。
"01" -> "00" ,执行的是第 1 种操作。

示例 2:

输入:n = 6
输出:4
解释:6 的二进制表示为 "110".
"110" -> "010" ,执行的是第 2 种操作,因为第 1 位为 1 ,第 0 到 0 位为 0 。
"010" -> "011" ,执行的是第 1 种操作。
"011" -> "001" ,执行的是第 2 种操作,因为第 0 位为 1 。
"001" -> "000" ,执行的是第 1 种操作。

提示:

  • 0 <= n <= 109

思路:

就是九连环。递推式:f(n*2)=f(n)*2+f(n)%2,f(n*2+1)=f(n)*2+1-f(n)%2

class Solution {
public:
    int minimumOneBitOperations(int n) {
        int x=n?minimumOneBitOperations(n/2):0;
        return x*2 + (n%2 ? 1-x%2 : x%2);
    }
};

POJ 1832 连环锁(九连环的推广)

题目:

许多人一定很熟悉九连环(如下图),九个环被串在一起,操作规则如下:第一个(右边)环可以任意装卸,如果第k个环没有被卸掉,而第k个环前边(右边)的所有环都被卸掉,则第k+1个环(第k个环左边的环)可以任意装卸(如果存在的话)。 
用0表示此换被卸掉,1表示此环没有被卸掉,则九连环的每个状态可以用一个长度为9的二进制串来表示,如:111111001经过一次操作可以变成111111000,也可以变成111111011,111111111经过一次操作可以变成111111110,也可以变成111111101。 

任务描述: 
你现在要操作的是一个n连环,n为正整数,给出n连环的两种状态,计算出从第一种状态变换到第二种状态所需要的最少步数。 
Input
第一行是一个正整数m,表示有m组测试数据。 
每组测试数据一共3行,第一行是一个正整数n (0 < n < 128),后两行每一行描述一种状态,n个数(0或1),用空格隔开。 
Output
对于每一组测试数据输出一行,一个非负整数,表示从第一种状态变换到第二种状态所需要的最少步数。
Sample Input
2
3
0 0 0
1 0 0
4
1 0 0 0
0 1 1 0
Sample Output
7
11

递推式并不难找,如果把状态看成1个二进制数,比如1000就是8,0110就是6,记为状态8、状态6
假设从状态n转移到转态0需要的最少步数为f(n),那么f就是上一题力扣1611的函数。

这样,只需要从左往右扫描就可以得出该状态的f()值,把2个状态的f()值相减即为2个转态之间转移的最少步数,这一点,可以从f()的定义(最小性)推导出来

代码:

​
import java.util.*;
import java.math.BigInteger;
public class Main 
{
	public static void main(String[] args) 
	{
	    Scanner cin = new Scanner(System.in);
		int m=Integer.parseInt(cin.next());
		while (m-->0)
		{
			int n=Integer.parseInt(cin.next());
			BigInteger a=new BigInteger("0"),b=new BigInteger("0");
			for(int i=0;i<n;i++)
			if(Integer.parseInt(cin.next())==0)a=a.multiply(BigInteger.valueOf(2)).add(a.mod(BigInteger.valueOf(2)));
			else a=a.multiply(BigInteger.valueOf(2)).add(BigInteger.valueOf(1)).subtract(a.mod(BigInteger.valueOf(2)));
			for(int i=0;i<n;i++)
			if(Integer.parseInt(cin.next())==0)b=b.multiply(BigInteger.valueOf(2)).add(b.mod(BigInteger.valueOf(2)));
			else b=b.multiply(BigInteger.valueOf(2)).add(BigInteger.valueOf(1)).subtract(b.mod(BigInteger.valueOf(2)));
			System.out.println(a.subtract(b).abs());  
		}	   
	}
}

​

buuctf(BUU CTF)是北京邮电大学举办的一项网络安全竞赛活动。九连环是其中的一道题目。 九连环是一个由九个环组成的智力游戏,目标是通过一系列的操作,将环从上到下按照一定的规则进行排列。这道题目可能要求我们编写一个程序来解决九连环的排列问题。 我们可以采用深度优先搜索(DFS)算法来解决该问题,该算法可以遍历所有可能的排列情况,并找到符合要求的解。具体步骤如下: 1. 定义一个长度为9的数组,用来表示九连环的初始排列。 2. 编写一个递归函数,该函数的目标是通过一系列的操作将九连环按照规则进行排列,同时记录每一个操作的过程。 3. 在递归函数中,使用循环遍历可能的操作情况,并以此对九连环进行操作。 4. 当九连环排列符合规则时,返回当前的排列和操作过程。 5. 当九连环没有符合规则的操作时,返回失败。 在解决该问题时,我们需要考虑以下几点: - 确定九连环的初始状态和目标状态。 - 设计合适的数据结构来存储操作过程和状态信息。 - 对递归函数进行合理的剪枝,以减少不必要的递归调用。 通过以上的思路和步骤,我们可以编写一个程序来解决九连环的排列问题。在BUU CTF中,我们可以使用该程序来解答九连环的题目,并提交给评测系统进行评判。最终得到正确的排列和操作过程,即可获得相应的分数和排名。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值