洛谷P1088 [NOIP2004 普及组] 火星人

news/2024/7/20 22:05:30 标签: 深度优先, 算法

传送门:https://www.luogu.com.cn/problem/P1088

一个全排列问题,可以把洛谷P1706写了再来写。

P1706: https://www.luogu.com.cn/problem/P1706

      看到题目的我的第一反应就是DFS,模拟全排列的过程,然后找到火星人给的排列顺序,然后接着往下找M个全排列就能找到答案。但是题目的数据开到10000,很明显这样的做法会超时。所以不能去慢慢找火星人给的顺序,应该是要在极短的时间内就锁定该排列在整个搜索过程中的位置,然后接着往下找M次。思路有了,怎么用代码实现呢?其他步骤都比较好些,关键是怎么快速找到火星人给的顺序? 

      由此引出该解法的核心代码跳转    if (!amount) i = ans[step];  读者可以先阅读代码段直到该行再翻上来看解释。

      这行核心代码实现的是跳转到这次搜索的起始位置。为什么这样写呢?先举一个1到5的全排列为例子,在用DFS实现1到5全排列的时候,第一个全排列是1 2 3 4 5 。由于在我们的搜索中有循环的存在,我们才得以枚举所有情况。那么如果把一个DFS的递归工作栈展开,就是一个多重循环,那么这个多重循环的i的值都不一样,都在特定的位置上,搜索到哪个数字就等于哪个数字。由于要快速找到火星人给的顺序,就必须确定该顺序的多重循环的每一个i的值。因此i=ans[step];ans存放的是火星人给的排列,由此可以确定每一个i。

#include<iostream>
#define MAX 10005
using namespace std;
int ans[MAX]; bool visit[MAX];
//ans数组用来存放排列顺序,visit标记
int M = 0, N = 0, amount = 0;bool flag = false;
//amount用于存储目前在哪个全排列
//flag是用来判别是否已经找到答案
void DFS(int step) {
	if (flag)return;
	//如果已经找到答案就一直return直到DFS函数结束
	if (step > N) {//边界
		amount++;//一个全排列就加1
		if (amount == M+1) {
			//这边的判定条件要注意是M+1
			//因为火星人最开始给出的排序也加进amount里
			flag = true;//找到了
			for (int i = 1; i <= N; i++)
				printf("%d ", ans[i]);
			//输出答案并return
			return;
		}
	}
	for (int i = 1; i <= N; i++)
	{
		if (!amount) i = ans[step];
		//核心代码,懂了后问题迎刃而解
		//跳转到该次DFS的相应位置
		//代码段外有详细解释
		if (!visit[i]) {
			visit[i] = true;
			ans[step] = i;
			DFS(step + 1);
			visit[i] = false;
		}
		//典型的全排列模板
		//如果不会可以先把 P1706的全排列问题研究明白再做这题
	}
}
int main(void)
{
	scanf("%d %d", &N, &M);
	for (int i = 1; i <= N; i++)
		scanf("%d", &ans[i]);
	DFS(1);//从1开始搜索
	return 0;//完结撒花
}


http://www.niftyadmin.cn/n/736563.html

相关文章

【Spring Cloud Alibaba Seata 处理分布式事务】——每天一点小知识

&#x1f4a7; S p r i n g C l o u d A l i b a b a S e a t a 处理分布式事务 \color{#FF1493}{Spring Cloud Alibaba Seata 处理分布式事务} SpringCloudAlibabaSeata处理分布式事务&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f98…

洛谷P3799 妖梦拼木棒

传送门&#xff1a;https://www.luogu.com.cn/problem/P3799 题目的标签是组合数学和暴力枚举。取四根木棒组成正三角形&#xff0c;显然有两根相等&#xff0c;形成两个边&#xff0c;还有两根&#xff08;这两根木棒有可能相等也有可能不等&#xff09;可以组成一条边。那么…

洛谷P4447 [AHOI2018初中组]分组

传送门&#xff1a;https://www.luogu.com.cn/problem/P4447 有一些贪心题目是可以通过直接观察例子得出贪心策略&#xff0c;即拿贪心策略去推断代码。我认为这个题目应该是由代码推断贪心策略&#xff0c;即先想想如果用代码怎么处理这样的问题&#xff0c;从而得出贪心策略…

洛谷P2678 [NOIP2015 提高组] 跳石头

传送门&#xff1a;https://www.luogu.com.cn/problem/P2678 非常同意一个观点&#xff1a;二分答案由二分区间和judge函数构成 二分答案&#xff0c;顾名思义&#xff0c;就是找到答案的范围区间&#xff0c;然后在这个区间里面去二分查找最优答案 该题目的答案区间显而易见…

gradle task 传递参数_Gradle系列之Groovy基础篇

原文首发于微信公众号&#xff1a;躬行之(jzman-blog)&#xff0c;欢迎关注交流&#xff01;上一篇学习了 Gradle 的入门知识&#xff0c;Gradle 基于 Groovy&#xff0c;今天学习一下 Groovy 的基础知识&#xff0c;Groovy 是基于 JVM 虚拟机的一种动态语言&#xff0c;语法与…

功率曲线k值_风机电机功率计算方法

选用的电机功率&#xff1a;N&#xff08;Q/3600&#xff09;*P/&#xff08;1000*η&#xff09;*K其中风量Q单位为m3/h&#xff0c;全压P单位为Pa&#xff0c;功率N单位为kW&#xff0c;η风机全压效率(按风机相关标准&#xff0c;全压效率不得低于0.7,实际估算效率可取小些,…

diskgenius创建efi分区_Windows磁盘分区教程

今天来聊一下磁盘的分区,可能会有朋友会碰见这样的情况,刚拿到一个新的电脑,里面的分盘只有一个或者有两个,感觉不太够用,所以想把某一个磁盘空间比较大的磁盘分出来一些重新新建一个盘。 对于这种情况,最简便的是使用电脑系统自带的压缩重新建立分区。过程如下: 首先,…

jst判断是否数组

// 判断是否数组const isArray (arg)> {if (typeof Array.isArray undefined) {return Object.prototype.toString.call(arg) [object Array]}return Array.isArray(arg) }