全排列 & 康托展开
# 去重全排列
#include<bits/stdc++.h>
using namespace std;
int num[100],cnt;
void fun(int pos,int n);
int judge(int l,int r);
int main()
{
int i,n;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",&num[i]);
fun(1,n);
system("pause");
return 0;
}
int judge(int l,int r)
{
for(;l<r;l++)
if(num[l]==num[r]) return 1;
return 0;
}
void fun(int pos,int n)
{
if(pos==n+1)
{
cnt++;
for(int i=1;i<=n;i++)
printf("%d%c",num[i],i==n?'\n':' ');
return ;
}
for(int i=pos;i<=n;i++)
{
if(judge(pos,i)) continue;
swap(num[pos],num[i]);
fun(pos+1,n);
swap(num[pos],num[i]);
}
}
# 康托
## 定义
康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。
## 康托展开
令X为全排列中的次序,num[]为原数组,n为全排列中数字的个数,为num[j] (j>i)小于num[i]的个数。
则
例:有(1,2,3,4,5)5个数的全排列中,计算34152的康托展开值。
通过定义可知,a[5] = 2 (1<3,2<3),a[4] = 2 (1<4,2<4),a[3] = 0 (无),a[2] = 1 (2<5),a[1] = 0 (无)。
又因为 n = 5,则X=2*4! + 2*3! + 0*2! + 1*1! + 0*0! = 61
所以在全排列中比34152小的有61个,即34152在全排列中排第62位(61+1=62)。
## 逆康托展开
因为康托展开是一个全排列到一个自然数的双射,所以可以通过61计算出34152。
有,得出
例:
61/4! = 2...13 则a[5] = 2,num[5]=3
13/3! = 2...1 则a[5] = 2,num[4]=4
1/2! = 0...1 则a[5] = 0,num[4]=1
1/1! = 1...0 则a[5] = 1,num[2]=5
则num[1]为剩下的数,num[1]=2
所以前面有61个排列,即第62个全排列为34152。
# 下一个全排列
26458173的下一个全排列为26458317。
步骤:
①从后往前找到第一个 的位置 (即样例中为1<7)
②从后往前找到第一个大于的数 x ,交换
和 x的位置 (
=1,x=3),得到26458371
③将位置 i 以后的数反转,得到26458317。
上一个全排列的求法与下一个全排列类似,自行解决。😒
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」