2006 年百度之星程序设计大赛初赛题目 3
变态的比赛规则
为了促进各部门员工的交流,百度 (baidu) 举办了一场全公司范围内的 " 拳皇友谊赛 " ,负责组织这场比赛的是百度的超级 " 拳皇 " 迷 W.Z. W.Z 不想用传统的淘汰赛或者循环赛的方式,而是自己制定了一个比赛规则。
由于一些员工(比如同部门或者相临部门员工)平时接触的机会比较多,为了促进不同部门之间的交流, W.Z 希望员工自己组成不同组。不同组之间的每两个人都会进行一场友谊赛而同一组内的人则之间不会打任何比赛。
比如 4 个人,编号为 1--4, 如果分为两个组并且 1,2 一个组, 3 , 4 一个组,那么一共需要打四场比赛: 1 vs 3,1 vs 4,2 vs 3,2 vs 4. 而如果是 1,2,3 一组, 4 单独一组,那么一共需要打三场比赛 : 1 vs 4,2 vs 4,3 vs 4.
很快 W.Z 意识到,这样的比赛规则可能会让比赛的场数非常多。 W.Z 想知道如果有 N 个人 , 通过上面这种比赛规则,总比赛场数有可能为 K 场吗?比如 3 个人,如果只分到一组则不需要比赛,如果分到两组则需要 2 场比赛 , 如果分为三组则需要 3 场比赛。但是无论怎么分都不可能只需要 1 场比赛。
相信作为编程高手的你一定知道该怎么回答这个问题了吧? 那么现在请你帮助 W.Z 吧。
输入
每行为一组数据,包含两个数字 N, K 。 (0<N<=500, K>=0)
输出
对输入的 N,K 如果 N 个员工通过一定的分组方式可能会一共需要 K 场比赛,则输出 "YES", 否则输出 "NO", 每组数据占一行。
所有的输入输出均为标准输入输出。
例子
输入文件 :
2 0
2 1
3 1
3 2
输出 :
YES
YES
NO
YES
基本方法:
1.根据人数,可以了解分组的数量的范围:1----总人数,即可以分 1组。。。。到=人数的组的数量
2。获得当前分组所有相加等于人数的组合,即路过要分4组,那么着4组人数总和=总人数,获得所有满足条件的组合,根据当前分的组数,取相应次数的人放置在组中,路分4组,那么取4次,每次取一部分人后放置其中,判断后面的剩余人数,需要满足后面组取的人数>=前面取的,我用1-1-1-1-2表示取人的数量和放置的组,- 是组的分割,数字是该组取的人数,由左到右人数依次增加,以避免排列
3.根据当前分组方式得到对应组合,计算每种组合的比赛次数等于目标次数的记录下来,放到数组中
4.最后打印结果,结果数组空,说明没有满足条件的
PHP代码:我测试的是 5人 目标比赛次数:9次,不同数据测试结果是不同的,可能没有结果,目标比赛次数过少,人过多,就可能没有结果
<?php
//比赛分组,达到目标比赛次数
$renshu=5;//总人数
$matchshu=9;//目标比赛次数
echo '当前比赛总人数:'.$renshu.' ;目标比赛次数'.$matchshu.'<br><br>';
$jieguo=array();
//由总人数可以知道分组方式 1--总人数
for($zhushu=1;$zhushu<=$renshu;$zhushu++){
$jishu=1;//分组的计数,标记分到第几组
$lian='';
$lianarr=array($lian);
$save=array();
//找到一种分组的所有有效的组合
while($jishu<=$zhushu){
$newarr=array();
//循环处理链
for($i=0;$i<count($lianarr);$i++){
$lian=$lianarr[$i];
//路过初始时,设置取的最小值,总和0
if($lian==''){
$zonghe=0;
$min=1;//最小的取值,必须大于等于它
}//end if($lian=='')
else{$t=explode('-',$lian);
$zonghe=array_sum($t);
$len=count($t)-1;
$min=$t[$len];
}
//判断是否可以取值,剩余的人数要平分后>=$min
$pingjun=($renshu-$zonghe)/($zhushu-$jishu+1);
//echo $pingjun;
//路过大于等于最小限制,说明可以有链取
if($pingjun>=$min){
for($i1=$min;$i1<=$pingjun;$i1++){
if($jishu==1)$newlian=$i1;
else $newlian=$lian.'-'.$i1;
$he=$zonghe+$i1;
if($he==$renshu)$save[]=$newlian;
else $newarr[]=$newlian;
}//end for($i1=$min;$i1<=$pingjun
}//end if($pingjun>=$min)
}//end for($i=0;$i<count($lianarr);$i++)
$lianarr=$newarr;
$jishu++;
}//end while($jishu<=$zhushu)
echo '分'.$zhushu.'组的所有组合:';
print_r($save);
//统计共有多少场比赛,寻找达到目标场数的组合
for($i=0;$i<count($save);$i++){
$lian=$save[$i];
$a=explode('-',$lian);
if(count($a)==1)$count=0;//路过只分一组,比赛数0
else{$count=0;$end=0;
for($i1=0;$i1<count($a)&&$end==0;$i1++){
for($i2=$i1+1;$i2<count($a)&&$end==0;$i2++){
$count=$count+$a[$i1]*$a[$i2];
if($count>$matchshu){$end=1;break;}//路过超过,直接跳出
}//end for($i2=$i1;$i2<count($a)
}//end for($i1=0;$i1<count($a)
}//end else{$count=0;
//echo $count;
if($count==$matchshu)$jieguo[]=$lian;
}//end for($i=0;$j<count($save);$i++)
echo '<br><br>';
}//end for($zhushu=1;$zhushu<=$renshu;$zhushu++)
echo '最后的满足条件的数组:';
print_r($jieguo);
echo '<br><br>';
if(empty($jieguo))echo '没有组合';
?>
本例测试输出录下:
当前比赛总人数:5 ;目标比赛次数9
分1组的所有组合:Array ( [0] => 5 )
分2组的所有组合:Array ( [0] => 1-4 [1] => 2-3 )
分3组的所有组合:Array ( [0] => 1-1-3 [1] => 1-2-2 )
分4组的所有组合:Array ( [0] => 1-1-1-2 )
分5组的所有组合:Array ( [0] => 1-1-1-1-1 )
最后的满足条件的数组:Array ( [0] => 1-1-1-2 )