算法:科克曼女生问题的一种解法
来源:互联网 发布:大数据公司销售好干吗 编辑:程序博客网 时间:2024/05/16 19:19
关于科克曼女生问题见http://baike.baidu.com/view/80040.htm详述,以下具体谈到一些算法方面问题。
1850年,科克曼(Kirkman)在《女士与先生之日记》杂志上发表了题为的文章,提出了15个女学生问题:
某寄宿学校的15个学生,每天都要3人一行的外出散步一次,怎样安排才能使得每个女生7天内核其他14个女生散步各一次。
- 初步分析估计:通过思考分析,7天,每天有5组,每组3人,七天就总共35组,35组肯定不可能出现两组是完全一样的搭配,那么实际上可能的组也就是一个15选3的一个无序排列组合,也就是455个可能。
- 第一步:那么这455个可能中,为了让每个女生都能够与其他女生都有结对过,那么最优的情况是看从中选取N组,使得这N组中,任意两组之间的交集不超过1,也就是不可能有两组是(A,B,C)与(A,B,D)在一起,那么这个也就是得通过设计一个简单的算法计算出这个N组为多少,而意外的是发现这个N=35,也就是说正好满足7天的安排,并且满足大组内全见面的条件。
- 第二步:这样通过算法得到了一个35个组,每组3个的一个列表,本以为问题就差不多,剩下的就是35组按条件拆分为7天的组合,保证每天内,每个人只出现在一个小组就行,后来发现这一步也不是那么简单,无回溯方式的探测,发现并不能将35组等分为7天,而是十天的组合,有的一天内只有三个小组,随后也就发现,这里的探测选取,有些支路并不符合,可能会导致走入死胡同,因此,应当记录探测分支,不符合的分支应当记录,并回溯,走其他分支进行探测。最终欣喜的得出一个答案:
( 1 2 3 ) ( 4 8 12 ) ( 5 10 15 ) ( 6 11 13 ) ( 7 9 14 )
( 1 4 5 ) ( 2 9 11 ) ( 3 12 15 ) ( 6 8 14 ) ( 7 10 13 )
( 1 6 7 ) ( 2 8 10 ) ( 3 13 14 ) ( 4 11 15 ) ( 5 9 12 )
( 1 8 9 ) ( 2 13 15 ) ( 3 4 7 ) ( 5 11 14 ) ( 6 10 12 )
( 1 10 11 ) ( 2 12 14 ) ( 3 5 6 ) ( 4 9 13 ) ( 7 8 15 )
( 1 12 13 ) ( 2 5 7 ) ( 3 8 11 ) ( 4 10 14 ) ( 6 9 15 )
( 1 14 15 ) ( 2 4 6 ) ( 3 9 10 ) ( 5 8 13 ) ( 7 11 12 )
本来就感觉这个应该是一个多解的问题(不是表面交换,而且搭配也会有变化),在做出来之后,参考百度百科,发现“西尔维斯特问题"更加抽象的概括这一问题,并且对于v=15,有13个不同的解。
那么对于另外12个解,个人就没有太多精力去全探测出来,但是从思路上判断,应该是第一步和第二部中的探测寻找选择起点位置进行更换(个人实现的算法中简化处理,找到一组解就行),这样可以得到解法的其他分支,并得到最后的结果。
最后个人的Java算法实现源码如下:
001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148package
puzzle;
import
java.util.HashSet;
import
java.util.LinkedList;
import
java.util.Set;
/**
* Class
*
* @author Vanjor
* @site http://www.vanjor.org
*
*/
public
class
PPair {
private
HashSet<Integer> pair =
new
HashSet<Integer>();
public
PPair(
int
x,
int
y,
int
z) {
pair.add(x);
pair.add(y);
pair.add(z);
}
public
HashSet<Integer> getPair() {
return
pair;
}
/**
* 判定两个Pair交集不大于1
*/
public
boolean
isSimilar(PPair p) {
Set<Integer> set =
new
HashSet<Integer>();
set.addAll(p.getPair());
set.addAll(pair);
if
(set.size() >
4
) {
return
false
;
}
else
{
return
true
;
}
}
/**
* 判断当前Pair与container是否有交集,有交集则返回false,无交集则返回true
*
* @param container
* @return
*/
public
boolean
isTotalDifferent(HashSet<Integer> container) {
for
(Integer index : pair) {
if
(container.contains(index)) {
return
false
;
}
}
return
true
;
}
public
String toString() {
StringBuffer sb =
new
StringBuffer();
sb.append(
"( "
);
for
(Integer mm : pair) {
sb.append(mm).append(
" "
);
}
sb.append(
")"
);
return
sb.toString();
}
public
static
final
int
SIZE =
15
;
public
static
LinkedList<PPair> getPairList() {
// 最原始的随机组合共455个
LinkedList<PPair> originaList =
new
LinkedList<PPair>();
// Pair交集不大于1的值剩下35个,正好为7*15
LinkedList<PPair> presentList =
new
LinkedList<PPair>();
for
(
int
index1 =
1
; index1 <= SIZE -
2
; index1++) {
for
(
int
index2 = index1 +
1
; index2 <= SIZE -
1
; index2++) {
for
(
int
index3 = index2 +
1
; index3 <= SIZE; index3++) {
originaList.add(
new
PPair(index1, index2, index3));
}
}
}
PPair seed =
null
;
while
(!originaList.isEmpty()) {
seed = originaList.remove();
presentList.add(seed);
LinkedList<PPair> tempList =
new
LinkedList<PPair>();
for
(PPair index : originaList) {
if
(seed.isSimilar(index)) {
tempList.add(index);
}
}
originaList.removeAll(tempList);
}
return
presentList;
}
public
static
LinkedList<LinkedList<PPair>> arrangeList(
LinkedList<PPair> list) {
// 结果7天的排列
LinkedList<LinkedList<PPair>> result =
new
LinkedList<LinkedList<PPair>>();
while
(!list.isEmpty()) {
LinkedList<PPair> tempList =
new
LinkedList<PPair>();
HashSet<Integer> dailyArrange =
new
HashSet<Integer>();
// 如果当次寻找不匹配,则跟据分支记录点回溯,另行分支再找
HashSet<PPair> failedArchives =
new
HashSet<PPair>();
// 每天为5组pair,保证15人全部出行
while
(tempList.size() <
5
) {
PPair branchRecord =
null
;
for
(PPair seed : list) {
if
(!failedArchives.contains(seed)
&& seed.isTotalDifferent(dailyArrange)) {
// 在分支尝试的时候,记住当前的分支
if
(tempList.size() ==
1
) {
branchRecord = seed;
}
tempList.add(seed);
dailyArrange.addAll(seed.getPair());
}
}
// 若本分支寻找配对失败,记录配对失败的Pair,重置其他记录状态
// 下次从其他分支开始尝试
if
(tempList.size() <
5
) {
tempList =
new
LinkedList<PPair>();
dailyArrange =
new
HashSet<Integer>();
failedArchives.add(branchRecord);
}
}
list.removeAll(tempList);
result.add(tempList);
}
return
result;
}
public
static
void
main(String[] args) {
LinkedList<PPair> pairList = getPairList();
LinkedList<LinkedList<PPair>> result = arrangeList(pairList);
// 打印结果
for
(LinkedList<PPair> row : result) {
for
(PPair pop : row) {
System.out.print(pop.toString() +
" "
);
}
System.out.println();
}
}
}
- 算法:科克曼女生问题的一种解法
- 科克曼女生问题
- 科克曼女生问题
- 科克曼女生问题
- 科克曼女生问题
- 科克曼女生问题
- 科克曼的十五名女生问题
- 一种背包问题的解法
- 糖果问题的一种解法
- wordBreak一种解法的算法分析
- "中国象棋将帅问题"的一种解法
- 打靶问题的一种递归解法
- 八皇后问题的一种解法
- 特殊的组合问题(另外一种解法)
- 0-1背包问题的一种解法
- 数字覆盖问题的一种解法
- 排列问题的其中一种解法
- 一种通用的SingleNumber问题解法
- 项目2-求分段函数
- Windows 7下 Windows Update被管理员禁用
- VC从文件全路径中获取文件名和扩展名方法
- 手把手教你如何配置和编译ogre 1.7.0 + cegui 0.7.1
- 玩转C语言数组各种算法小结
- 算法:科克曼女生问题的一种解法
- Percona-Server5.5——mysql安装配置
- codeforces 俄罗斯季度决赛题目sequence解答
- 用printchs输出符号
- 在XML中加入皮肤后,最好专门建一个skin文件
- div+css制作圆角宽度定宽边框
- 任务三 输出形状图
- 第十二周上级任务三之后调用自定义函数改写任务二版
- vIDC2.0 端口映射工具