组合数的序号问题
来源:互联网 发布:java 支付宝支付 demo 编辑:程序博客网 时间:2024/05/29 04:34
组合{2,4}的序号为5。一般而言,令
则可得如下递推公式:
令
因此递推公式可重新表述为
反复用这个公式可得
它可以被用在动态规划法求TSP之中,借助于它就能够实现一般参考书上所说的时间复杂度。TSP的具体实现见附录1。
附录---MATLAB代码
function [pmin,pvmin]=tspdp(D)
%TSPDP 旅行销售员问题(TSP)的动态规划(Dynamic Programming)算法的递推实现
%
% [pmin, pvmin] = tspdp( D )
% 输入参数:D --- 两两城市之间的距离矩阵,双精度二维数组
% 输出参数:pmin --- 最短路线双精度,一维行数组
% pvmin --- 最短距离,双精度数
%
% Example: [pmin,pvmin]=tspdp(rand(5))
%
% 注意:经分析,其时间复杂度为O(n*2^n),也就是说n 每增大1,运行时间大致上变成
% 原来的2 倍。因此,n不能太大,当取在12以内时,速度很快。若用C++等实现,在20以
% 内都可以接受。
n=length(D);
pasmat=pascal(n+1);
fP=calfP(D,pasmat);
pvmin=inf;
for j=1:n-1
v=fP{n-1}(j,1)+D(j,n);
if pvmin>v
pvmin=v;
jmin=j;
end
end
pmin=zeros(1,n+1);
pmin(n:n+1)=[jmin, n];
C=1:n-1;
for j=n-1:-1:1
Csn=combineseqnum(C,n-1,j,pasmat);
I=find(pmin(j+1)==C);
pmin(j)=fP{j}(I,2,Csn);
C(I)=[];
end
%------------------------------------------------------------------------
function fP=calfP(D,pasmat)
n=length(D);
for k=1:n-1
fP{k}=zeros(k,2,pasmat(k+1,n-k));
end
for Csn=1:n-1
fP{1}(:,:,Csn)=[D(n,Csn),n];
end
for k=2:n-1
C=zeros(1,k);
Csn=0;
curi=1;
while curi
if C(curi)>=n-1-k+curi
curi=curi-1;
else
C(curi:end)=C(curi)+1:C(curi)+1+k-curi;
curi=k;
Csn=Csn+1;
S=C(2:k);
for I=1:k
CI=C(I); %后面要重复使用
Ssn=combineseqnum(S,n-1,k-1,pasmat);
vmin=inf;
for j=1:k-1
v=fP{k-1}(j,1,Ssn)+D(S(j),CI);
if vmin>v
vmin=v;
jmin=S(j);
end
end
fP{k}(I,:,Csn)=[vmin, jmin];
if I<k
S(I)=CI;
end
end
end
end
end
%-----------------------------------------------------------------------
function sn=combineseqnum(p,n,r,pasmat)
%COMBINESEQNUM 求{1,2,...,n}中抽取r个数构成的组合在所有组合(升序)按字典序排
% 序后所处的序号(从1开始编号)。
%
% sn = combineseqnum(p , n)
% 输入参数:p --- {1,2,...,n}的一个组合,用数值向量表示,行或列均可,要求按
% 升序排列
% n --- 元素的个数,即{1,2,...,n}中的 n
% r --- p中元素的个数
% pasmat --- 帕斯卡矩阵
% 输出参数:sn --- p在所有组合中的按字典序排序后的编号
%
% Example: sn=combineseqnum([1 3],4)
%
if r>1
sn=pasmat(r+1,n-r+1);
for I=1:r
nn=n-p(I);
rr=r+1-I;
if nn>=rr
sn=sn-pasmat(rr+1,nn-rr+1);
end
end
else
sn=p;
end
C++代码
// 求{1,2,...,n}中抽取r个数构成的组合在所有组合(升序)按字典序排序后所处的序号(从1开始编号)。 // 输入参数:// n --- 元素的个数,即{1,2,...,n}中的 n// p --- {1,2,...,n}的一个组合,要求按升序排列// r --- p中元素的个数// n_choose_k --- 帕斯卡三角形// 返回值: p在所有组合中的按字典序排序后的编号int combineseqnum(const int n,const vector<int>& p,const vector<vector<int>>& n_choose_k){int sn(0);int r=p.size();if(r>1){sn=n_choose_k[n][r];int nn(0),rr(0);for(int k=0;k<r;++k){nn=n-p[k]-1;rr=r-k;if(nn>=rr)sn-=n_choose_k[nn][rr];}--sn;}else{sn=p[0];}return sn;}void get_n_choose_k(int n,vector<vector<int>>& n_choose_k){for(int i=1;i<=n+1;++i)n_choose_k.push_back(vector<int>(i,1));for(auto ir=n_choose_k.begin()+2;ir!=n_choose_k.end();++ir){auto ic=ir->begin()+1;auto icp=(ir-1)->begin()+1;for(;ic!=ir->end()-1;++ic,++icp)*ic=*(icp-1)+*icp;}}
- 组合数的序号问题
- 数的组合问题
- 关于序号的问题
- 组合数计算问题的总结
- 三个数求加法组合的问题
- 钱币组合方法数的问题
- 8595 钱币组合方法数的问题
- 数的组合问题(递归)
- 放球问题的组合数 总结
- 组合数相关的一些问题
- 有关组合数越界的问题
- 一道组合数问题
- 组合数问题
- NYOJ 组合数问题
- NOIP2016day2t1 组合数问题
- 组合数问题
- [NOIP2016] 组合数问题
- NOIP2016组合数问题
- VB6.0数据库访问技术与例程解析(三)
- C ERRORS(http://www.tutorials4u.com/c/t90.htm)
- C ERRORS(http://www.tutorials4u.com/c/t90.htm)
- 设备驱动中环形缓冲区数据存储和读写同步的实现
- Tomcat中文的问题
- 组合数的序号问题
- Mobile Agents
- 折纸痕问题 Paper Folding
- 动态申请二维数组。
- 保存图片到数据库
- 一个15岁少年写的汇编代码
- 生成集合[n]的所有k-子集MATLAB代码
- 记今天看到的和做的小事
- 产生[n]所有置换