全排列

PTA ― 7-19 输出全排列 (20 分)

匿名 (未验证) 提交于 2019-12-03 00:11:01
7-19 输出全排列 (20 分) 请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。 输入格式: 输入给出正整数n(<10)。 输入样例: 3 输出样例: 123 132 213 231 312 321 # include <stdio.h> int a [ 10 ] , b [ 10 ] , n ; void dfs ( int step ) { if ( step == n + 1 ) { for ( int i = 1 ; i <= n ; i ++ ) printf ( "%d" , a [ i ] ) ; printf ( "\n" ) ; return ; } for ( int i = 1 ; i <= n ; i ++ ) { if ( b [ i ] == 0 ) { a [ step ] = i ; b [ i ] = 1 ; dfs ( step + 1 ) ; b [ i ] = 0 ; } } return ; } int main ( ) { scanf ( "%d" , & n ) ; dfs ( 1 ) ; return 0 ; } 来源:51CTO 作者: 王睿丶 链接:https://blog.csdn.net/qq_27494201/article/details

寻找全排列的下一个数(字典序算法实现)

匿名 (未验证) 提交于 2019-12-03 00:03:02
给出一个正整数,找出这个正整数所有数字全排列的下一个数。通俗的说就是在一个整数所包含数字的全部组合中,找到一个大于且仅大于原数的新整数。举例: 如果输入:12345,则返回12354 如果输入:12354,则返回12435 如果输入:12435,则返回12453 思路: 字典序算法: 从后向前查看逆序区,找到逆序区域的前一位,作为数字置换的边界; 逆序区是指:数字大小(从左到右)排序一定会是从大到小。 所以从右往左找,第一个右边值大于左边值的位置,那么右边这个位置就是逆序区的起始点。 从右向左,从逆序区中找到大于【逆序区域起始点的前一位A】的最小的数字B,将A,B交换位置 因为逆序区的数字大小(从右到左)排序一定会是从小到大,所以只要从右向左找,第一个大于A的就一定也是逆序域中大于A的最小数字。 所以,从右向左遍历,找到第一个大于A的数字,就可以直接交换位置,退出循序。 把原来的逆序区域转为顺序状态; 同样的,因为逆序区的数字大小(从右到左)排序一定会是从小到大,所以只要从逆序区的两端,头尾值两两交换即可 举例: 1736542,逆序区域:6542,那么逆序区的起始点就是6,然后将3和4交换位置,变为:1746532,将逆序区域转为顺序状态:1742356。 代码实现: 1 import java.util.Arrays; 2 3 /** 4 * 寻找全排列的下一个数 5 *

NOIP提高组 模拟赛 Day1

匿名 (未验证) 提交于 2019-12-02 23:56:01
T1 单峰数计数 Description 一个n的全排列A[i]是单峰的,当且仅当存在某个x使得A[1]<A[2]<...<A[x]>A[x+1]>...> A[n]。例如,对于9的全排列,125798643是一个单峰排列,123456789也是一个单峰排列,但356298741就不是。试求n的单峰全排列的个数。 Input 输入一个数n。 Output 输出n的全排列中单峰排列的个数。由于这个数可能很大,因此你只需要输出它mod 1234567的值。 Sample Input 3 Sample Output 4 Hint ##### 样例解释 共有以下4种方案: 123 132 231 321 ##### 数据规模 对于20%的数据,n<=25。 对于100%的数据,n<=2*10^9。 对于100%的数据,显然时间复杂度在O(logn)以下。 所以~手动打表找规律。 当n=1时 只有1种情况:1 当n=2时 有2种情况:12 21 当n=3时 有4种情况:即样例解释 当n=4时 有8种情况:1234 1243 1342 1432 2341 2431 3421 4321 当n=5时 有16种情况:12345 12354 12453 12543 13452 13542 14532 15432 23451 24531 23541 25431 34521 35421 45321

luogu P5367 【模板】康托展开 / P2518 [HAOI2010]计数

泪湿孤枕 提交于 2019-12-02 04:57:15
今天学习 康托展开 和 可重集康托展开。。。 康托展开。。就是给你一个1~n全排列,问它的排名。。 例如:x1, x2 , x3 , x4 , x5 是一个1~5的全排列,现在我们要求它的排名。。 从第1位开始枚举。。 然后枚举j,当然这个j要< xi ,并且不能在x(1~i-1)中出现过。 发现当 j < xi 时 ,后面无论怎样填,都会比所求排列的字典序小。。所以就是! (len-i) 。累加到答案中。 枚举完j后,就令第i位为xi,将xi标记上即可,后面枚举 j 时就不能在枚举到 xi了。 考虑优化枚举 j 这个过程。。 开个树状数组。记录一下前面1~i-1出现过那些数,合法的j的个数即为xi-1-ask(xi - 1)啦,直接乘上 ! (len-i) 即可。。 最后add(xi)。。 然后就是蛤OI的这道计数题啦。。 只不过是可以有相同的元素罢了。。 把上面枚举j统计答案乘!(len-i)的过程改为乘上后面剩余元素可重集的全排列即可。。 其他的大致相同。。这个玩意就不能用树状数组了,只能老老实实枚举 j 。。 由于这个题它TM不取模,,搞得求可重集的全排列的过程很难搞。。 虽然最后结果不会爆long long 但中间也可能会爆。。 所以我们就不能直接按求可重集的全排列的公式来求了。。 用组合数。。而由于我是个蒟蒻,不会用符号,就没有办法演示了。。看代码吧。。

剑指offer 28:字符串的排列

ぃ、小莉子 提交于 2019-12-02 02:02:46
题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 输入描述 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。 解题思路 本题解题思路与存在重复数字的数组的全排列思路相同。需要完成排列去重的工作。因而工作分为两步。第一,确定当前数组元素的全排列;第二,对排列结果去重。 1.无论对于数组还是字符串,使用递归实现全排列的过程最容易,对于一个字符串而言,他的所有全排列可视为由第一个字符与剩余所有字符全排列的连接。而对于剩余字符,又可视为剩余字符中第一个字符,与其他剩余字符全排列的连接,依次递归。 2.对于去重,使用哈希地址映射,快速去重,简单讲就是使用set数据类型存储得到的所有全排列,最终set集合中得到的就是去重后的结果。 C++代码实现 class Solution { public: vector<string> Permutation(string str) { vector<string> result; int sz=str.size(); if(sz==0){ return result; } Permutation_sub(str,0,result); set<string> st(result.begin(),

局部敏感哈希LSH(Locality-Sensitive Hashing)——海量数据相似性查找技术

旧巷老猫 提交于 2019-12-01 17:16:22
一、 前言     最近在工作中需要对海量数据进行相似性查找,即对微博全量用户进行关注相似度计算,计算得到每个用户关注相似度最高的TOP-N个用户,首先想到的是利用简单的协同过滤,先定义相似性度量(cos,Pearson,Jaccard),然后利用通过两两计算相似度,计算top-n进行筛选,这种方法的时间复杂度为 \(O(n^2)\) (对于每个用户,都和其他任意一个用户进行了比较)但是在实际应用中,对于亿级的用户量,这个时间复杂度是无法忍受的。同时,对于高维稀疏数据,计算相似度同样很耗时,即 \(O(n^2)\) 的系数无法省略。这时,我们便需要一些近似算法,牺牲一些精度来提高计算效率,在这里简要介绍一下MinHashing,LSH,以及Simhash。 二、 MinHashing     Jaccard系数是常见的衡量两个向量(或集合)相似度的度量: \[ J(A,B)=\frac {\left | A\cap B \right |}{\left | A\cup B \right |} \]     为方便表示,我们令A和B的交集的元素数量设为 \(x\) ,A和B的非交集元素数量设为 \(y\) ,则Jaccard相似度即为 \()\frac x {(x+y)}\) 。 所谓的MinHsah,即进行如下的操作: 对A、B的 \(n\) 个维度,做一个随机排列(即对索引 \(

CSP-J/S 知识点选的

戏子无情 提交于 2019-12-01 15:11:28
CSP-J/S 知识点选讲 信息学史及基本知识 一、信息学及计算机史 计算机的顶级奖项 :图灵奖 对信息科学做出突出贡献的大神 : 图灵 , 冯 · 诺伊曼 中国获图灵奖的大神 :姚期智(清华就有姚班,就是以他的名字命名的) 世界第一台电子计算机 :埃尼阿克(ENIAC),于1946年2月14日在美国宾夕法尼亚大学诞生。又被叫做电子管计算机。 二、关于编程 编程语言 : 分两类:面向对象和面向过程。 高级语言和低级语言的区别 : 高级语言需要编译运行,常数较大,运行速度慢。而低级语言常数极小,运行速度快。此外,高级语言更容易移植。 常见低级语言 : 汇编 面向对象的高级语言 : C++,Java,EIFFEL,Simula 67等。 面向过程的高级语言 : C,Fortran语言。 递归编程 : 递归是指一种通过重复将问题分解为同类的子问题而解决问题的方法。递归式方法可以被用于解决很多的计算机科学问题。简单来讲,就是“自身调用自身”(在函数中)。 P类/NP类/NPC类问题 : 1、P类问题:如果一个问题能找到一个在多项式时间内解决它的算法,那么这个问题就是P问题。 2、NP类问题:注意:NP问题 不是非P类问题 ,而是在多项式时间内验证一个解的问题。或者,我们可以将其理解为在多项式时间内猜出一个解的问题。 3、NPC类问题:定义如下:如果一个问题是NP问题

CSP-J/S 知识点选讲

两盒软妹~` 提交于 2019-12-01 13:39:46
CSP-J/S 知识点选讲 信息学史及基本知识 一、信息学及计算机史 计算机的顶级奖项 :图灵奖 对信息科学做出突出贡献的大神 : 图灵 , 冯 · 诺伊曼 中国获图灵奖的大神 :姚期智(清华就有姚班,就是以他的名字命名的) 世界第一台电子计算机 :埃尼阿克(ENIAC),于1946年2月14日在美国宾夕法尼亚大学诞生。又被叫做电子管计算机。 二、关于编程 编程语言 : 分两类:面向对象和面向过程。 高级语言和低级语言的区别 : 高级语言需要编译运行,常数较大,运行速度慢。而低级语言常数极小,运行速度快。此外,高级语言更容易移植。 常见低级语言 : 汇编 面向对象的高级语言 : C++,Java,EIFFEL,Simula 67等。 面向过程的高级语言 : C,Fortran语言。 递归编程 : 递归是指一种通过重复将问题分解为同类的子问题而解决问题的方法。递归式方法可以被用于解决很多的计算机科学问题。简单来讲,就是“自身调用自身”(在函数中)。 P类/NP类/NPC类问题 : 1、P类问题:如果一个问题能找到一个在多项式时间内解决它的算法,那么这个问题就是P问题。 2、NP类问题:注意:NP问题 不是非P类问题 ,而是在多项式时间内验证一个解的问题。或者,我们可以将其理解为在多项式时间内猜出一个解的问题。 3、NPC类问题:定义如下:如果一个问题是NP问题

【学习笔记】全排列

旧巷老猫 提交于 2019-11-30 18:19:11
今天模拟赛最后一题暴力骗分没骗到,特此下定决心搞懂全排列 1.全排列的定义和公式: 从n个数中选取m(m<=n)个数按照一定的顺序进行排成一个列,叫作从n个元素中取m个元素的一个排列。由排列的定义,显然不同的顺序是一个不同的排列。从n个元素中取m个元素的所有排列的个数,称为排列数。从n个元素取出n个元素的一个排列,称为一个全排列。全排列的排列数公式为n!,通过乘法原理可以得到。 2.时间复杂度: n个数(字符、对象)的全排列一共有n!种,所以全排列算法至少时间O(n!) 的。如果要对全排列进行输出,那么输出的时间要O(n∗n!) ,因为每一个排列都有n个数据。所以实际上,全排列算法对大型的数据是无法处理的,而一般情况下也不会要求我们去遍历一个大型数据的全排列。 # 例题 luogu全排列问题 法1: STL大法好! #include<bits/stdc++.h> #define rep(a,b,c) for(int a=b;a<=c;a++) using namespace std; int x[11]; int n; int main() { scanf("%d",&n); rep(i,1,n) { x[i]=i, printf(" %d",i); } while(next_permutation(x+1,x+1+n)) { printf("\n"); rep(i,1,n)

火星人 题解

孤人 提交于 2019-11-29 19:44:25
题目描述 人类终于登上了火星的土地并且见到了神秘的火星人。人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法。这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科学家,科学家破解这个数字的含义后,再把一个很小的数字加到这个大数上面,把结果告诉火星人,作为人类的回答。 火星人用一种非常简单的方式来表示数字――掰手指。火星人只有一只手,但这只手上有成千上万的手指,这些手指排成一列,分别编号为 1,2,3… 1 , 2 , 3 …。火星人的任意两根手指都能随意交换位置,他们就是通过这方法计数的。 一个火星人用一个人类的手演示了如何用手指计数。如果把五根手指――拇指、食指、中指、无名指和小指分别编号为 1,2,3,4 1 , 2 , 3 , 4和 5 5,当它们按正常顺序排列时,形成了 5 5位数 12345 1 2 3 4 5,当你交换无名指和小指的位置时,会形成 5 5位数 12354 1 2 3 5 4,当你把五个手指的顺序完全颠倒时,会形成 54321 5 4 3 2 1,在所有能够形成的 120 1 2 0个 5 5位数中, 12345 1 2 3 4 5最小,它表示 1 1; 12354 1 2 3 5 4第二小,它表示 2 2; 54321 5 4 3 2 1最大,它表示 120 1 2 0。下表展示了只有 3 3根手指时能够形成的 6