一个数学题

jacketzhou 2005-10-20 07:57:47
有a,b,c,d,e,f,g,h,i,j,k,l,m,n共14个字母


分别组成9个字母一组a,b,c,d,e,f,g,h,i

这14个字母分别能组成多少组,用ASP要怎么写才能全部显示出来呢?
...全文
710 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
jacketzhou 2005-10-21
  • 打赏
  • 举报
回复
多谢各位的回复,但经过考虑我想的问题是这样的,应当得出以下结果,14个字母的位置是不变动的
- b c d e f g h i j - - - -
- b c d e f g h i - k - - -
- b c d e f g h i - - l - -
- b c d e f g h i - - - m -
- b c d e f g h i - - - - n
a - c d e f g h i j - - - -
a - c d e f g h i - k - - -
a - c d e f g h i - - l - -
a - c d e f g h i - - - m -
a - c d e f g h i - - - - n
a b - d e f g h i j - - - -
a b - d e f g h i - k - - -
a b - d e f g h i - - l - -
a b - d e f g h i - - - m -
a b - d e f g h i - - - - n
a b c - e f g h i j - - - -
a b c - e f g h i - k - - -
a b c - e f g h i - - l - -
a b c - e f g h i - - - m -
a b c - e f g h i - - - - n
a b c d - f g h i j - - - -
a b c d - f g h i - k - - -
a b c d - f g h i - - l - -
a b c d - f g h i - - - m -
a b c d - f g h i - - - - n
a b c d e - g h i j - - - -
a b c d e - g h i - k - - -
a b c d e - g h i - - l - -
a b c d e - g h i - - - m -
a b c d e - g h i - - - - n
a b c d e f - h i j - - - -
a b c d e f - h i - k - - -
a b c d e f - h i - - l - -
a b c d e f - h i - - - m -
a b c d e f - h i - - - - n
a b c d e f g - i j - - - -
a b c d e f g - i - k - - -
a b c d e f g - i - - l - -
a b c d e f g - i - - - m -
a b c d e f g - i - - - - n
a b c d e f g h - j - - - -
a b c d e f g h - - k - - -
a b c d e f g h - - - l - -
a b c d e f g h - - - - m -
a b c d e f g h - - - - - n
jacketzhou 2005-10-21
  • 打赏
  • 举报
回复
不明白的是for i=cdbl(&h01234) to cdbl(&hdcba9)
为何不的取值范围是4660 - 904105,这个范围是根据什么得来的
jacketzhou 2005-10-21
  • 打赏
  • 举报
回复
共得出3941个结果
jacketzhou 2005-10-21
  • 打赏
  • 举报
回复
结果是出来了,说真的,只看懂一点,但是有点慢
asp_m 2005-10-21
  • 打赏
  • 举报
回复
学习中,,楼上的都是高手
这些知识是从哪里学的呢? 这个讨论的是关于数据结构的么?
belldandy11 2005-10-21
  • 打赏
  • 举报
回复
学习
wanghui0380 2005-10-21
  • 打赏
  • 举报
回复
哦,没看到你最后的补充,我心急了点

如果加上你后面的补充,即位置是不变动,那么这个问题就简单了
呵呵,问题简化成了,从14个数里挑五个去掉
转成数学描述:生成一个14进制的5位数,且每位数不相等
<%


temp="a,b,c,d,e,f,g,h,i,j,k,l,m,n"

rs1=split(temp,",")
dim rs2(13)
for i=0 to 13
rs2(i)=0
next
for i=cdbl(&h01234) to cdbl(&hdcba9) //循环从&h01234到&hdcba9,这个循环比较大,我本机测试用了2分钟,你可以考虑更改循环的值,分步得到结果
temp2=hex(i)
if len(temp2)=4 then temp2="0"+temp2
if(instr(temp2,"E")<=0 and instr(temp2,"F")<=0) then
b=""
for j=1 to 5
a=Mid(temp2, j, 1)
if instr(b,a)>0 then
for m=0 to 13
rs2(m)=0
next
exit for
else
b=b&a
rs2(eval("&h"+a))=1
if j=5 then
res=""
for m=0 to 13
if rs2(m)=0 then
res=res+rs1(m)
end if
rs2(m)=0
next
if(instr(res1,res)<=0) then
response.write res+"<br>"
res1=res1+res+","
end if
end if
end if
next
end if
next






jacketzhou 2005-10-21
  • 打赏
  • 举报
回复
又明白了一点,其实还没有完全懂,谢谢这位兄弟的答复
wanghui0380 2005-10-21
  • 打赏
  • 举报
回复
我上面的做法是一种偷懒的做法,这样做会使循环的长度加大
标准做法:是直接使用14进制和10进制互换,不过这样写就得自己写转换函数了(应该是个递归函数)
14进制数01234转成10进制为:1*14^3+2*14^2+3*14+4=3182
14进制数dcba9转成10进制为:13 * 14^4 +12 * 14^3 + 11 * 14^2 + 10*14+9=534641

wanghui0380 2005-10-21
  • 打赏
  • 举报
回复
考虑你要求14位,即 0,1,2,3,4,5,6,7,8,9,A,B,C,D
由上面的数字能排成的5位不重复的16进制的最小值:&h01234
由上面的数字能排成的5位不重复的16进制的最大值:&hdcba9
wanghui0380 2005-10-21
  • 打赏
  • 举报
回复



5位不重复的16进制的最大值

考虑你要求14位,即 0,1,2,3,4,5,6,7,8,9,A,B,C,D
5位不重复的16进制的最小值
wanghui0380 2005-10-21
  • 打赏
  • 举报
回复
换个思考方式:问题等同9位的14进制数有多少个
这个进制比较特殊,可是如果是9位16进制呢?计算就方便了,只要使用hex()函数就可以得到结果,可是这样一来结果就多了,不过没关系,我们抛弃掉结果含e,f的就可以出来正确的结果了
不过这样的计算数据很大,很容易溢出和超时,让我算法复杂度低的算法看看

大体上估算一下结果的数量
类比一下10进制算法:9位数的数量=1000000000-100000000=9000000000
可以得到16进制算法:

a=&h10000000*&h100 //10位16进制起点,因为&h1000000000溢出,所以用&h10000000*&h100得到
b=&h10000000*&h10 //9位16进制起点
response.write (a-b)*14/16 //乘14/16,是指你的那14个数在16进制中出现的概率

结果56371445760 ,呵呵,天文数字!!看来无论怎么写都不是在短时间内能算出来的







jacketzhou 2005-10-20
  • 打赏
  • 举报
回复
多谢回位回复,我测试看看哪个写得好,到时再给分
超级大笨狼 2005-10-20
  • 打赏
  • 举报
回复

<SCRIPT LANGUAGE=VBS>
'全排列的字典算法
dim n, i, j, k, temp
dim arr() '全局数组
n =6 : redim arr(n)
'数组赋初值
for i = 1 to n
arr(i) = i
next
document.write join(arr) & "<br>"
do
'从右到左找到第一个比右边数字小的数字位置
for j = n - 1 to 1 step -1
if arr(j) < arr(j + 1) then exit for
next
'结束则跳出循环
if j = 0 then exit do
'找出这个数右边比他大的最小数
for k = n to j + 1 step -1
if arr(k) > arr(j) then exit for
next
'交换之 (k, j)
temp = arr(j)
arr(j) = arr(k)
arr(k) = temp
'升序排列 j + 1 到 n
MySort j + 1, n
'打印一个结果
document.write join(arr) & "<br>"
loop
'升序排列, 冒泡法
function MySort(i, j)
dim k, m, temp
if i >= j then exit function

for m = j to i + 1 step -1
for k = i to m - 1
if arr(k) > arr(k + 1) then
temp = arr(k)
arr(k) = arr(k + 1)
arr(k + 1) = temp
end if
next
next
end function
</SCRIPT>

超级大笨狼 2005-10-20
  • 打赏
  • 举报
回复
程序如下:

program effi;

var i,j,k,n,m,l:integer;

d,r1,r2,r3,t:real;

r:array[1..3,1..3] of real;

procedure init; {输入效率表}

var i,j,k:integer;

begin

for i:=1 to 3 do

for j:=1 to 3 do

read(r[i,j]);

end;

procedure prt; {打印输出}

begin

writeln('worker',' ':8,'type',' ':8,'effi':8);

writeln('a',n:15,r1:15);

writeln('b',m:15,r2:15);

writeln('c',l:15,r3:15);

end;

begin {主程序}

d:=0;

for i:=1 to 3 do

for j:=1 to 3 do

for k:=1 to 3 do

if (i<>j) and (j<>k) and (i<>k) then

begin

t:=r[1,i]+r[2,j]+r[3,k];

if d<t then

begin

d:=t;n:=i;m:=j;l:=k;

r1:=r[1,i]+r[2,j]+r[3,k];

end;

end;

prt;

end.

上例中,工人人数及工种数和效益表都是题中给定的(工人3人,工种也是3种)。

若工人人数,工种及效率表都不事先给定,而是要求程序运行后从键盘输入,那么

题目难度将增大,见下例。

例3:N个工人,分配到M个工种干活(M≤N),每个工种只能分配一人。N,

M及每个工人从事各工种的效率按下列格式从键盘输入:

n=? 4 (工人总数)

m=? 4 (工种总数)

g1: 3 4 2 5 (工人1从事各工种的效率)

g2: 6 2 1 3 (工人2从事各工种的效率)

g3: 5 4 4 2 (工人3从事各工种的效率)

g4: 1 3 2 4 (工人4从事各工种的效率)

试问:如何分配才能使总效益最大?

分析:由于N,M的值是程序运行后,方从键盘输入的,所以无法利用多重循环

来设计程序。我们可以这样来考虑:用1,2,3...N表示N名工人,从中选出M 个按照

工种的顺序排列。这样每一种排法就对应了一种分配方案。所以他们可以利用上一

节介绍的排列组合算法二,生成从N个元素中任选M个元素的全部排列,逐个判断求

出效益最大的一种分配方案。

程序如下:

program pailie(input,output);

var

a,aa:array[1..20] of integer;

b:array[1..100,1..100] of integer;

i,j,t,r,k,n,m,h,step,step1,step2:integer;

begin

write('input n=');

readln(n); {输入工人人数}

write('input m=');

readln(m); {输入工种数}

t:=1;step:=0;

for j:=1 to n do {输入效率表}

begin

a[j]:=0;

write('g',j,' ');

for h:=1 to m do

read(b[j,h]);

end;



repeat {以下产生n个中取m个的排列}

a[t]:=a[t]+1;

if a[t]>n then

t:=t-1

else

begin

r:=0;

for i:=1 to t-1 do

if a[t]=a[i] then r:=100; {r=100是重复标志}

if r<>100 then

begin

if t=m then {t=m表示完成一种排列}

begin

step1:=0;

for h:=1 to m do

step1:=step1+b[h,a[h]]; {计算效率之和}

if step1>step then {保存当前效率最大时分配方案}

begin

for step2:=1 to m do

aa[step2]:=a[step2];

step:=step1

end;

end;

if t<m then begin t:=t+1;a[t]:=0; end;

end;

end;

until t=0;

for step2:=1 to m do {打印输出}

write('G(',step2,',',aa[step2],')');

writeln('=',step);

end.

请同学们认真将此程序与上一节介绍的排列组合算法二程序对照一下,从而可以

体会到上一节所介绍的排列、组合及算法的重要性。





排列的递归算法



列出所有从数字1到数字n的连续自然数的排列,要求所产生的任一数字序列中不允许

出现重复的数字

输入:n(1<=n<=9)

输出:

程序如下:

procdure find(k:integer);

begin

if k > n

then 输出a[1]—a[n]的值

else

for i:=1 to n do

begin

if i的值与a[1]--a[k-1]无重复

then

begin

a[k]:=i

找下一个路口

end

end

end;
超级大笨狼 2005-10-20
  • 打赏
  • 举报
回复
排列、组合及算法
[日期:2005-08-25] 来源: 作者: [字体:大 中 小]
排列,组合是高中数学中的基本内容之一。我们在程序设计中对具体问题进行

分析,建立数学模型时会经常涉及到这方面的知识。因此,掌握排列、组合及算法

是学习程序设计和掌握其它算法的基础。

一:排列、组合概念

定义1:从N个不同元素中,任选M个元素(M≤N),按照一定的顺序排成一队,

叫做从N个元素中取M个元素的一个排列。当M=N时叫做N的全排列。

定义2:从N个不同元素中,任选M个元素(M≤N)而不考虑其次序时, 称为从N

个元素中取M个元素的一个组合。

例1:一个小组中有四名同学,选出其中三人到三个车间参加劳动。问:共有

多少种不同的分配方案?

分析:我们用1,2,3,4表示这四名同学。把三个车间看做分别固定在从左到右

的位置上不动,然后从四名同学中任选三人按从左向右的顺序排成一队,这就对应

一种分配方案。所以这是一个从四个不同元素中任选三个元素的排列问题。共有如

下24种排法:(如图11.0所示)

┌────────┬────────┬────────┐

1│ 2│ 3│ 4│

│ │ │ │

┌──┼──┐ ┌──┼──┐ ┌──┼──┐ ┌──┼──┐

2│ 3│ 4│ 1│ 3│ 4│ 1│ 2│ 3│ 1│ 2│ 3│

│ │ │ │ │ │ │ │ │ │ │ │

┌┴┐┌┴┐┌┴┐┌┴┐┌┴┐┌┴┐┌┴┐┌┴┐┌┴┐┌┴┐┌┴┐┌┴┐

│ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ │

│ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ ││ │

3 4 2 4 2 3 3 4 1 4 1 3 2 4 1 4 1 2 2 3 1 3 1 2

(图11.0)

从上到下,各边的标号就是一种排列,从左到右依次为:

123,124,132,134,142,143,213,214,231,234,241,243,312,314,321,324,341

,342,412,413,421,423,431,432。

例2:有甲、乙、丙、丁四位同学,从中选出三位同学参加义务劳动. 问:有

多少种不同的选法?

分析:我们用1,2,3,4表示这四位同学,由于选出的三们同学与顺序无关,所

以这是从四个不同元素中选三个元素的组合问题。共有如下四种不同的选法:

123,124,134,234。



二:求排列、组合方案的基本算法──循环嵌套

例3: 从1,2,3,4,5这五个数中任选三个,不许重复.问:共能组成多少个不同的

三位数,并把它们打印出来。

分析:显然这是一个从五个不同元素中任选三个元素的排列问题。我们可以利

用三重循环来解决.循环变量的取值范围为1--5。在内循环体内加入判断,排除取值

两两重复的情况。程序如下:

program pl;

var a,b,c,t:integer;

begin

t:=0;

for a:=1 to 5 do

for b:=1 to 5 do

for c:=1 to 5 do

if (a<>b) and (a<>c) and (b<>c) then

begin

writeln(a,b,c); {打印一种排列方案}

t:=t+1; {t:统计总数}

end;

writeln('Total: ',t);

end.

例4:有甲、乙、丙、丁、戊、己六位同学,从中任选三位同学做游戏, 问:共

有多少种不同的选法,并把结果打印出来。

分析:由于选出的三位同学是做游戏与顺序无关,所以这是一个从六个不同元

素中任选三个元素的组合。我们用1,2,3,4,5,6表示这六位同学,选法共有如下20种:

123,124,125,126,134,135,136,145,146,156,

234,235,236,245,246,256,345,346,356,456。

从上面的组合生成过程中,可以看出如下规律:

1、最后一位数字可达N(上例中N=6),倒数第二位最大可达N-1,...依次类推,

倒数第K位不得超过N-K+1

2、对于每一种组合,从左向右观察,左边的数字均小于右边的数字。

根据以上规律,我们同样可利用三重循环来解决这个问题。最外层的循环变量

A,对应最左边一位数字,变化范围为1--4;第二层循环变量B对应中间一位数字,变

化范围为(A+1)--5;内循环变量C对应最右边一位数字,变化范围(B+1)--6。程序

如下:

program zh;

var

a,b,c,t:integer

begin

t:=0;

for a:=1 to 4 do

for b:=a+1 to 5 do

for c:=b+1 to 6 do

begin

writeln(a,b,c);

t:=t+1;

end;

writeln('Total: ',t);

end.



三、求排列、组合方案的算法二

上面介绍的用多重循环产生排列,组合数的方法有两点不足之处。第一,受循

环嵌套层次的限制(一般不能超过八层)。第二,必须给出n,m的确切值,即选出元

素的个数必须在编程前确定,因为他决定了循环嵌套的层次。但有些问题却往往是n,

m的值在程序运行中才从键盘输入的。此时就无法用上述方法编程。下面我们介绍

产生排列,组合数的另一种方法。它是在深入分析排列组合数产生规律的基础上,编

程实现的。

首先,让我们回过头来观察一下例1中排列数产生的规律:

123,124,132,134,142,143

213,214,231,234,241,243

312,314,321,324,341,342

412,413,421,423,431,432。

第一个排列数123是按自然数顺序产生。 然后最高位递增,当达到最大值N时,退一

位,考虑倒数第二位递增1,其后各位仍由小到大逐个递增(当然整个过程中不许有重

复数字出现),当倒数第二位达到最大值N时,再退一位考虑...。下面先给出实现此

算法的程序框架。

┌──────────┐

│ 初始化: │

│ 输入N,M=?,T=1 │ (m≤n)

│ a[1],...a[n]=0 │

└──────────┘

/ repeat

│ a[t]=a[t]+1

│ ┌──────────┐

│ │ if a[t]>n then │

│ │ a[t]=0,t=t-1 │

│ │ goto 100 │

│ └──────────┘

│ ┌──────────┐

│ │ for i=1 to t-1 │

│ │ if a[t]=a[i] then│ (排除重复情况}

│ │ goto 100 │

│ └──────────┘

│ ┌──────────┐

│ │ if t<m then │

│ │ t=t+1, a[t]=0 │(若是组合,改为a[t]=a[t-1])

│ │ goto 100 │

│ └──────────┘

│ ┌──────────┐

│ │ if t=m then │

│ │ 打印一种排法 │

│ └──────────┘

\ 100: until t=0



按上述程序框架编写的源程序如下:

program pailie(input,output);

var

a:array[1..20]of integer;

i,j,t,r,k,n,m,step:integer;

begin

writeln('input n,m (n>m) ');

readln(n,m);

t:=1;step:=0;

for j:=1 to m do

a[j]:=0;

/repeat

│ a[t]:=a[t]+1;

│ if a[t]>n then

│ t:=t-1

│ else

│ begin

│ r:=0;

│ for i:=1 to t-1 do

│ if a[t]=a[i] then r:=100;

│ if r<>100 then

│ begin

│ if t=m then

│ / begin

│ │ step:=step+1;

│ │ write(step:4,') '); {打印输出}

│ │ for k:=1 to t do

│ │ write(a[k]);

│ │ writeln;

│ \ end;

│ if t<m then

│ begin

│ t:=t+1;a[t]:=0; {将a[t]:=0改为a[t]:=a[t-1],则为组合}

│ end;

│ end;

│ end;

\ until t=0;

end.



例2:某工厂录取三个职工,分配到三个工种,每个工种各分配一人, 经过技

术测定,三个工人担任某项工作的生产率如表11.1。问:这三个工人如何分配才能

使做出的总贡献最大?









┌──┬──┬───┬───┐

│ │ 甲│ 已 │ 丙 │

├──┼──┼───┼───┤

│ 1 │ 3 │ 5 │ 2 │

├──┼──┼───┼───┤

│ 2 │ 4 │ 3 │ 3 │

├──┼──┼───┼───┤

│ 3 │ 2 │ 4 │ 3 │

└──┴──┴───┴───┘

分析:我们用变是A、B、C表示甲,已,丙三名工人,变量的值表示所担任的工种.

如:A=1,B=3,C=2表示工人A做1号工种,工人B做3号工种,工人C做2号工种。A、B、

C的取值范围均为1--3,且两两不重复,即同一工种不能被两人担任。A、B、C 的一

组不重复取值就为一种分配方案。我们可利用三重循环来生成所有可能的分配方案,

从中选出效益最大的一种。为了减少排序时间,程序中将初始最大效率D=0,然后

以此来逐一比较求解。

超级大笨狼 2005-10-20
  • 打赏
  • 举报
回复
排列组合与回溯算法
作者: 来自: 阅读次数: 99 [大 中 小]
--------------------------------------------------------------------------------

排列组合与回溯算法

KuiBing

感谢Bamboo、LeeMaRS的帮助

[关键字] 递归 DFS

[前言] 这篇论文主要针对排列组合对回溯算法展开讨论,在每一个讨论之后,还有相关的推荐题。在开始之前,我们先应该看一下回溯算法的概念,所谓回溯:就是搜索一棵状态树的过程,这个过程类似于图的深度优先搜索(DFS),在搜索的每一步(这里的每一步对应搜索树的第i层)中产生一个正确的解,然后在以后的每一步搜索过程中,都检查其前一步的记录,并且它将有条件的选择以后的每一个搜索状态(即第i+1层的状态节点)。

需掌握的基本算法:

排列:就是从n个元素中同时取r个元素的排列,记做P(n,r)。(当r=n时,我们称P(n,n)=n!为全排列)例如我们有集合OR = {1,2,3,4},那么n = |OR| = 4,切规定r=3,那么P(4,3)就是:

{1,2,3}; {1,2,4}; {1,3,2}; {1,3,4};{1,4,2};{1,4,3};{2,1,3};{2,1,4}; {2,3,1}; {2,3,4}; {2,4,1}; {2,4,3}; {3,1,2}; {3,1,4}; {3,2,1}; {3,2,4}; {3,4,1}; {3,4,2}; {4,1,2}; {4,1,3}; {4,2,1}; {4,2,3}; {4,3,1}; {4,3,2}

算法如下:

int n, r;
char used[MaxN];
int p[MaxN];

void permute(int pos)
{ int i;
/*如果已是第r个元素了,则可打印r个元素的排列 */
if (pos==r) {
for (i=0; i<r; i++)
cout << (p[i]+1);
cout << endl;
return;
}
for (i=0; i<n; i++)
if (!used[i]) { /*如果第i个元素未用过*/
/*使用第i个元素,作上已用标记,目的是使以后该元素不可用*/
used[i]++;
/*保存当前搜索到的第i个元素*/
p[pos] = i;
/*递归搜索*/
permute(pos+1);

/*恢复递归前的值,目的是使以后改元素可用*/
used[i]--;
}
}


相关问题

UVA 524 Prime Ring Problem


可重排列:就是从任意n个元素中,取r个可重复的元素的排列。例如,对于集合OR={1,1,2,2}, n = |OR| = 4, r = 2,那么排列如下:

{1,1}; {1,2}; {1,2}; {1,1}; {1,2}; {1,2}; {2,1}; {2,1}; {2,2}; {2,1}; {2,1}; {2,2}

则可重排列是:

{1,1}; {1,2}; {2,1}; {2,2}.

算法如下:

#define FREE -1
int n, r;
/*使元素有序*/
int E[MaxN] = {0,0,1,1,1};
int P[MaxN];
char used[MaxN];

void permute(int pos)
{
int i;
/*如果已选了r个元素了,则打印它们*/
if (pos==r) {
for (i=0; i<r; i++)
cout << P[i];
cout << endl;
return;
}
/*标记下我们排列中的以前的元素表明是不存在的*/
P[pos] = FREE;
for (i=0; i<n; i++)
/*如果第I个元素没有用过,并且与先前的不同*/
if (!used[i] && E[i]!=P[pos]) {
/*使用这个元素*/
used[i]++;
/*选择现在元素的位置*/
P[pos] = E[i];
/*递归搜索*/
permute(pos+1);
/*恢复递归前的值*/
used[i]--;
}
}


相关习题

UVA 10098 Generating Fast, Sorted Permutations


组合:从n个不同元素中取r个不重复的元素组成一个子集,而不考虑其元素的顺序,称为从n个中取r个的无重组合,例如OR = {1,2,3,4}, n = 4, r = 3则无重组合为:

{1,2,3}; {1,2,4}; {1,3,4}; {2,3,4}.

算法如下:

int n, r;
int C[5];
char used[5];

void combine(int pos, int h)
{
int i;
/*如果已选了r个元素了,则打印它们*/
if (pos==r) {
for (i=0; i<r; i++)
cout<< C[i];
cout<< endl;
return;
}
for (i=h; i<=n-r+pos; i++) /*对于所有未用的元素*/
if (!used[i]) {
/*把它放置在组合中*/
C[pos] = i;
/*使用该元素*/
used[i]++;
/*搜索第i+1个元素*/
combine(pos+1,i+1);
/*恢复递归前的值*/
used[i]--;
}
}


相关问题:

Ural 1034 Queens in peaceful position


可重组合:类似于可重排列。

[例] 给出空间中给定n(n<10)个点,画一条简单路径,包括所有的点,使得路径最短。

解:这是一个旅行售货员问题TSP。这是一个NP问题,其实就是一个排列选取问题。

算法如下:

int n, r;
char used[MaxN];
int p[MaxN];
double min;

void permute(int pos, double dist)
{
int i;
if (pos==n) {
if (dist < min) min = dist;
return;
}
for (i=0; i<n; i++)
if (!used[i]) {
used[i]++;
p[pos] = i;
if (dist + cost(point[p[pos-1]], point[p[pos]]) < min)
permute(pos+1, dist + cost(point[p[pos-1]], point[p[pos]]));
used[i]--;
}
}


[例]对于0和1的所有排列,从中同时选取r个元素使得0和1的数量不同。

解 这道题很简单,其实就是从0到2^r的二元表示。

算法如下:

void dfs(int pos)
{
if (pos == r)
{
for (i=0; i<r; i++) cout<<p[i];
cout<<endl;
return;
}
p[pos] = 0;
dfs(pos+1);
p[pos] = 1;
dfs(pos+1);}


相关问题:

Ural

1005 Stone pile

1060 Flip Game
1152 The False Mirrors


[例]找最大团问题。

一个图的团,就是包括了图的所有点的子图,并且是连通的。也就是说,一个子图包含了n个顶点和n*(n-1)/2条边,找最大团问题是一个NP问题。算法如下:

#define MaxN 50

int n, max;
int path[MaxN][MaxN];
int inClique[MaxN];

void dfs(int inGraph[])
{
int i, j;
int Graph[MaxN];

if ( inClique[0]+inGraph[0]<=max ) return;
if ( inClique[0]>max ) max=inClique[0];

/*对于图中的所有点*/
for (i=1; i<=inGraph[0]; i++)
{
/*把节点放置到团中*/
++inClique[0];
inClique[inClique[0]]=inGraph[i];
/*生成一个新的子图*/
Graph[0]=0;
for (j=i+1; j<=inGraph[0]; j++)
if (path[inGraph[i]][inGraph[j]] )
Graph[++Graph[0]]=inGraph[j];
dfs(Graph);
/*从团中删除节点*/
--inClique[0];}
}
int main()
{
int inGraph[MaxN];
int i, j;
cin >>n;
while (n > 0)
{
for (i=0; i<n; i++)
for (j=0; j<n; j++)
cin >>path[i][j];
max = 1;
/*初始化*/
inClique[0]= 0;
inGraph[0] = n;
for (i=0; i<n; i++) inGraph[i+1]=i;
dfs(inGraph);
cout<<max<<endl;
cin >>n;
}
return 0;}



超级大笨狼 2005-10-20
  • 打赏
  • 举报
回复
<INPUT id=t1 value=5><br>
<INPUT id=t2 value=5><br>
<INPUT id=t3 value=5><br>
<INPUT id=t4 value=1>
<p id=p></p>
<button onclick=vbs:SuperDullWolf id=button1 name=button1>笨狼24点牌DHTML递归算法</button>
<SCRIPT LANGUAGE=vbscript >
dim a(4),f(4),last
'计算4个数字的全排列
sub SuperDullWolf
dim count:count=0'计算无解的次数
p.innerHTML=""
for i1 =1 to 4
for i2 =1 to 4
for i3 =1 to 4
for i4 =1 to 4
if not(i1=i2 or i1=i3 or i1=i4 or i2=i3 or i2=i4 or i3=i4) then
a(1)=cint(eval("t" & i1 & ".value"))
a(2)=cint(eval("t" & i2 & ".value"))
a(3)=cint(eval("t" & i3 & ".value"))
a(4)=cint(eval("t" & i4 & ".value"))
if Iis24(a,4) then '如果找到答案就退出
exit sub
else
count=count+1'如果找不到答案继续尝试其他组合
end if
end if
Next
Next
Next
Next
if count>=24 then msgbox count & "无解!"
end sub
function sum(x,y,z)
on error resume next
sum=x
select case z
case 1
sum=sum+y
case 2
sum=sum-y
case 3
sum=sum*y
case 4
sum=sum/y
end select
last=x
end function
function showsum(x,y,z)
'显示
showsum=cstr(x)
select case z
case 1
showsum= showsum & "+" & y
case 2
showsum=showsum & "-" & y
case 3
showsum=showsum & "*" & y
case 4
showsum=showsum & "/" & y
end select
end function
function Iis24(ByRef a(),ByRef i)
if i=2 then
'如果剩下两个数直接判断
n1=a(1)
n2=a(2)'读入这两个数
for ff=1 to 4'遍历加减乘除
if sum(n1,n2,ff)=24 then
'输出结果
p.innerHTML=p.innerHTML & showsum(n1,n2,ff) & "=" & cstr(sum(n1,n2,ff)) & "<br>"
Iis24=true
exit function
else
if sum(n2,n1,ff)=24 then
'输出结果
p.innerHTML=p.innerHTML & showsum(n2,n1,ff) & "=" & cstr(sum(n2,n1,ff)) & "<br>"
Iis24=true
exit function
end if
end if
next
else
'如果有i个数,先去出两个来进行加减乘除
dim b(4),c(4)
for ii=1 to i
'取第一个数
n1=a(ii)
for jj=1 to i
if jj<>ii then
n2=a(jj)
'剩余放入数组C
nb=2
for kk=1 to i
if kk<>ii and kk<>jj then
c(nb)=a(kk)
nb=nb+1
end if
next
end if
next
for ff=1 to 4'便历加减乘除
c(1)=sum(n2,n1,ff) '取出两个数放到c中
if Iis24(c,i-1) then'递归
if sum(n2,n1,ff)=last then
p.innerHTML=p.innerHTML & showsum(n1,n2,ff) & "=" & sum(n1,n2,ff) & "<br>"
else
p.innerHTML=p.innerHTML & showsum(n2,n1,ff) & "=" & sum(n2,n1,ff) & "<br>"
end if
Iis24=true
exit function
end if
next
next
end if
end function
</SCRIPT>
超级大笨狼 2005-10-20
  • 打赏
  • 举报
回复
<SCRIPT LANGUAGE=vbs>
'10多行代码实现n个数字全排列
dim n:n=4
dim S
dim w:w=0
for i=1 to n
S=S & "for i" & i & " =1 to n" & chr(13)
next
S=S & " if not("
for i=1 to n
for j=i to n
if i<>j then S=S & "i" & i & "=i" & j & " or "
next
next
S=left(S,len(S)-4) & ") then " & chr(13)
for i=1 to n
S=S & "document.write i" & i & chr(13)
next
S=S & "document.write " & chr(34) & "<br>" & chr(34) & chr(13) & "end if" & chr(13)
w=w+1
for i=1 to n
S=S & "Next" & chr(13)
next
execScript S,"vbs"
</SCRIPT>

28,406

社区成员

发帖
与我相关
我的任务
社区描述
ASP即Active Server Pages,是Microsoft公司开发的服务器端脚本环境。
社区管理员
  • ASP
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧