- 注册时间
- 2015-10-15
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 2202
- 在线时间
- 小时
|
楼主 |
发表于 2021-7-7 21:58:57
|
显示全部楼层
本帖最后由 TSC999 于 2021-7-8 06:06 编辑
本帖目的在主帖中说了,是为了改进常新德老师(河南永城职业学院)大约在 2008 年写的论文《有重复元素的圆排列和环排列的计数问题》。见网址:https://max.book118.com/html/2017/0729/125132578.shtm
对于有 m 种颜色,每种颜色的珠子分别有 n(1)、n(2)、......、n(m) 颗,能穿成多少种花色的手串问题(手串共有 n(1)+n(2)+......+n(m) 颗珠子),论文给出的计算公式中,要求各种颜色的珠子数目,至多只能有两个是奇数。
这就限制了应用范围。比如现在有 3 种颜色红、绿、黄,其中红珠 3 颗,绿珠 1 颗, 黄珠 1 颗,由于每种颜色的珠子数目都是奇数,不符合公式约定的 “珠子数目至多只能有两个是奇数” 这一要求, 所以计算结果是一个分数。
如果把分数结果取整,舍掉小数部分,好像能得到正确结果。为了验证这个想法是否正确,我们必须事先写一个计算程序作为裁判,以便由程序给出一个可信赖的结果。
我用 mathematica 初步写了一个程序,似能正确运行,但是尚缺最后一步即如何加上一个循环语句。
在程序中设定共有红、绿、黄 3 种颜色即 m=3。其中红珠 3 颗,绿珠 1 颗,黄珠 1 颗。对于这种非常简单的情况,只有 2 种可能的花色,见下图。
程序调试成功后,可将颜色数目和各色珠子数量随意修改。目前程序尚未最终完成,但程序能给出正确的计算结果。程序如下:
- Clear["Global`*"];
- Array[a, 20];
- ss = {}; (* 所有的方案数列表 *)
- a = Permutations[{"黄", "绿", "红", "红",
- "红"}, {5}]; (* 5个有重复元素的全排列,a 是个列表*)
- L = Length[a]; (* 共有多少种线排列? *)
- (* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% *)
- s = a[[1]]; (* 候选方案*)
- ss = Append[ss, s];
- s1 = Reverse[s]; (* 候选方案反排*)
- Do[If[a[[i]] == s || a[[i]] == s1, a[[i]] = {}], {i, 2,
- L}]; (* s 左移,s1右移之前,先筛一次 *)
- Do[s = RotateLeft[s];
- s1 = RotateRight[s1]; (* s 左移一位,并存到 s 中; s1右移一位,并存到 s1 中*)
- Do[If[a[[i]] == s || a[[i]] == s1, a[[i]] = {}], {i, 2, L}];
- , {i, 1,
- 4}]; (* s每左移一位、s1每右移一位,与其余的比较,若有一个是相同的,将那个其余清空。共筛 4 次 *)
- a = DeleteCases[a, {}]; (* 去掉 a 中的所有空集 *)
- a = Delete[a, 1] (* 去掉 a 中的候选方案 a[[1]] 后的 a 列表 *)
- L = Length[a] (* 筛一轮后的 a 还有多少种线排列? *)
- If[L == 0, Print[ss, " 所有方案展示"]];
- Print[" ########################################## "];
- s = a[[1]]; (* 候选方案*)
- ss = Append[ss, s];
- s1 = Reverse[s]; (* 候选方案反排*)
- Do[If[a[[i]] == s || a[[i]] == s1, a[[i]] = {}], {i, 2,
- L}]; (* s 左移,s1右移之前,先筛一次 *)
- Do[s = RotateLeft[s];
- s1 = RotateRight[s1]; (* s 左移一位,并存到 s 中; s1右移一位,并存到 s1 中*)
- Do[If[a[[i]] == s || a[[i]] == s1, a[[i]] = {}], {i, 2, L}];
- , {i, 1,
- 4}]; (* s每左移一位、s1每右移一位,与其余的比较,若有一个是相同的,将那个其余清空。共筛 4 次 *)
- a = DeleteCases[a, {}]; (* 去掉 a 中的所有空集 *)
- a = Delete[a, 1] (* 去掉 a 中的候选方案 a[[1]] 后的 a 列表 *)
- L = Length[a] (* 筛一轮后的 a 还有多少种线排列? *)
- If[L == 0, Print[ss, " 所有方案展示"]];
- Print[" ########################################## "];
复制代码
上面这程序运行结果为:
上面程序尚存在毛病,因为有两段相邻程序是完全相同的,必须把它们放进一个 While 循环语句中去以控制循环次数才行。试改如下:
- Clear["Global`*"];
- Array[a, 20];
- ss = {}; (* 所有的方案数列表 *)
- a = Permutations[{"黄", "绿", "红", "红",
- "红"}, {5}]; (* 5个有重复元素的全排列,a 是个列表*)
- L = Length[a]; (* 共有多少种线排列? *)
- (* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% *)
- While[L > 0,
- s = a[[1]]; (* 候选方案*)
- ss = Append[ss, s];
- s1 = Reverse[s]; (* 候选方案反排*)
- Do[If[a[[i]] == s || a[[i]] == s1, a[[i]] = {}], {i, 2,
- L}]; (* s 左移,s1右移之前,先筛一次 *)
- Do[s = RotateLeft[s]; s1 = RotateRight[s1]; (* s 左移一位,并存到 s 中;
- s1右移一位,并存到 s1 中*)
- Do[If[a[[i]] == s || a[[i]] == s1, a[[i]] = {}], {i, 2, L}];
- , {i, 1, 4}]; (* s每左移一位、s1每右移一位,与其余的比较,若有一个是相同的,将那个其余清空。共筛 4 次 *)
- a = DeleteCases[a, {}]; (* 去掉 a 中的所有空集 *)
- a = Delete[a, 1] (* 去掉 a 中的候选方案 a[[1]] 后的 a 列表 *)
- L = Length[a] (* 筛一轮后的 a 还有多少种线排列? *)
- If[L == 0, Print[ss, " 所有方案展示"]];
- Print[" ########################################## "];
- ]
复制代码
上面这样改动以后程序不能运行。不知应当如何改才行?
补充内容 (2021-7-8 12:03):
程序中第 2 行的 Array[a, 20]; 无用,应该去掉。
补充内容 (2021-7-9 08:54):
上面加入 While 循环语句后程序出错,问题是 While 循环内的所有语句后必须用分号才行。改正后的程序见下页。 |
|