主题:优化算法!紧急!
Mato完整版
[专家分:1270] 发布于 2008-05-14 12:30:00
输入N个数(5<=N<=100),要求把它们分成M组,分组时要符合三个要求:
(1)每组至少有一个数。
(2)每组除第一个数外,每一个数都不能小于前一个数。
(3)每组的所有数必须都是N个数中的,且不能改变位置(即原来N个数中,I在J之前,则I、J如果分在同一组的话,I还要在J之前)。
求怎么分才能使M最小,输出M及分法。
【样例输入】
N= 6
4
5
11
6
8
13
【样例输出】
M= 2
4 5 6 8 13
11
最后更新于:2008-05-14 22:09:00
回复列表 (共8个回复)
沙发
Mato完整版 [专家分:1270] 发布于 2008-05-14 12:32:00
除了枚举、递归、回溯之外的所有算法都给分。
板凳
Mato完整版 [专家分:1270] 发布于 2008-05-14 22:09:00
我已经写出来了程序:
DECLARE SUB nodown (s!())
DECLARE SUB clearzero (s!())
DECLARE FUNCTION nozero! (sss!())
CLS
INPUT nn
DIM SHARED ss(1 TO nn, 1 TO 2)
DIM a(1 TO nn)
FOR i = 1 TO nn: INPUT a(i): NEXT i
DO
CALL nodown(a())
FOR i = UBOUND(ss, 1) TO 1 STEP -1
PRINT ss(i, 1);
a(ss(i, 2)) = 0
NEXT i
PRINT
CALL clearzero(a())
m = m + 1
LOOP UNTIL nozero(a()) = 0
PRINT "M="; m
END
SUB clearzero (s())
p = nozero(s())
IF p = 0 THEN EXIT SUB
DIM s2(1 TO p)
pp = 0
FOR i = 1 TO UBOUND(s)
IF s(i) <> 0 THEN
pp = pp + 1: s2(pp) = s(i)
END IF
NEXT i
REDIM s(1 TO pp)
FOR i = 1 TO pp: s(i) = s2(i): NEXT i
END SUB
SUB nodown (s())
n = UBOUND(s)
DIM t(1 TO n), m(1 TO n)
t(1) = 1: m(1) = 0
FOR i = 2 TO n
k = 0: x = 0
FOR j = i - 1 TO 1 STEP -1
IF s(i) >= s(j) AND k < t(j) THEN
k = t(j)
x = j
END IF
NEXT j
t(i) = k + 1
IF k <> 0 THEN m(i) = x
NEXT i
k2 = 1: kk = 1
FOR i = 2 TO n
IF t(i) > k2 THEN k2 = t(i): kk = i
NEXT i
REDIM ss(1 TO k2, 1 TO 2)
FOR i = 1 TO k2
ss(i, 1) = s(kk)
ss(i, 2) = kk
kk = m(kk)
NEXT i
END SUB
FUNCTION nozero (sss())
nz = 0
FOR i = 1 TO UBOUND(sss)
IF sss(i) <> 0 THEN nz = nz + 1
NEXT i
nozero = nz
END FUNCTION
REM 子程序说明:
REM 过程nodown:对数组S中的元素求最长的非降序列的过程,序列存放到ss数组中。
REM 过程clearzero:将数组S中的所有零清除掉,只保留非零数字。
REM 函数nozero:求数组SSS中非零元素的个数的函数。
现在程序是写好了,可是问题又出来了:
(1)这个程序是采用一种贪心的思路编的,即每次都取最长的非降序列。这样对某些数据就通不过了,如
N=7
3
8
4
9
5
10
6
最少只要分2组(3,4,5,6)和(8,9,10),但我的程序却把它分成了3组。
(2)这个程序的M是在最后输出的,而样例输出中的却是最先输出的,怎么办?
3 楼
老大徒伤悲 [专家分:29120] 发布于 2008-05-15 19:16:00
算法名词我不懂。
但我有个想法:
对n个元素,就建立n*n的二维数组来存放结果。(显然有点奢侈了)
把第一个元素放在结果数组的最开始;
对第二个元素开始以下的每一个元素,检查结果数组的每一维的最后一个非零元素,如果大于当前元素,检查下一维;否则写入其后;所有非空维都检查完了,仍不能写入,则写入下一维的开头。
处理完后,输出非空维数,输出各维元素。
4 楼
moz [专家分:37620] 发布于 2008-05-15 19:32:00
N=7
3,8,4,9,5,10,6
3,8, 9, 10
4, 5, 6
5 楼
staa [专家分:3690] 发布于 2008-06-26 12:33:00
用“取大优先”(这里是取小优先)的方法一般可以找到较优解:
寻找第一个被保留的数(存放在BaoLiu()数组中),它是未选数列中最小的数;下一个数就是当前数;
当前数与最后一个BaoLiu()数比较,如果小,则剔除最后一个BaoLiu()数,然后继续比较;大则保留,作为最后一个BaoLiu()数(不应该有相等的情况吧?如果相等也剔除),下一个数就是当前数,重复这一过程,这样就能得到一个由最小数开头的数列,输出它们,并清空BaoLiu()数组;
然后再在被剔除的数中重复上面的过程,直到被剔除的数的个数小于2(1个或0个)。
注意这是个较优解,如果不是很特别,它一般就是最优解了。
6 楼
staa [专家分:3690] 发布于 2008-06-26 13:04:00
上面只是一个大体的算法,写代码时还要注意一些细节。
7 楼
staa [专家分:3690] 发布于 2008-06-26 13:37:00
更简化的方案:
A、所有的数均为未选数;
B、在未选数中找到最小数,输出该数,并在数列中剔除之;
C、之后的数列均为未选数,如果个数大于1,则->B;等于1,则输出之,并在数列中剔除之;并标记完成一组(包括个数为0);
D、所有未剔除的数的个数大于1,则->A;等于1,则输出之,并标记完成工作(包括个数为0)。
这个算法差不多可以直接写代码了。
里面有两个过程,一个是找最小数,一个是在数列中剔除一个数。
8 楼
staa [专家分:3690] 发布于 2008-06-26 21:00:00
程序出来了:
'下面的程序不保证M最小,只能说在一般情况下M应该是最小的
'
DEFINT A-Z
RANDOMIZE TIMER
INPUT "n=0:exit, n=[5,99] ", n
IF n = 0 THEN END
IF n > 99 THEN n = 99
IF n < 5 THEN n = 5
PRINT "n="; n
DIM a(n) AS INTEGER
FOR i = 1 TO n
a(i) = RND * 100
PRINT a(i);
Next
'以上生成并显示n个随机整数
PRINT
Print
m = 1
Print m;" ";
b = a(1)
w = 1
'上二行为初始定义,b是最小值,w是最小值的位置,以下进入主题
DO WHILE n > 1
FOR i = w + 1 TO n
IF a(i) < b THEN b = a(i): w = i
NEXT
PRINT b;
'以上是找出最小数并显示之
IF w = n THEN
Print
m=m+1
Print m;" ";
b = a(1)
w = 1
'以上如果最小数是最后一个数,则结束一轮
ELSE
FOR i = w + 1 TO n
a(i - 1) = a(i)
Next
'如果最小数不是最后一个数,则后面的数列均前移一位(刚才找到的最小数被覆盖)
END IF
n = n - 1
b = a(w)
'上二行定义新的查找范围(注意这里有语句共用,本人的不良习惯,结构化的编程不要这样写)
LOOP
IF n = 1 THEN PRINT a(n)
PRINT "game over."
END
运行的结果还比较满意:
70 69 70 19 79 70 6 15 11
1 6 11
2 15
3 19 70
4 69 70 79
5 70
19 6 4 76 32 45 78 6 8 39 55 25 28 77 74
1 4 6 8 25 28 74
2 6 32 39 55 77
3 19 45 78
4 76
我来回复