良問ですね。
鍋あり谷あり:[プログラミング]あなたならどうお書きになります1.0クリスマスパーティーでプレゼント交換を行う。この条件を満たすようなプレゼント交換が等確率で出るような、プレゼント交換方法生成プログラムを実装せよ
- 全員、誰かにプレゼントを一つあげ、誰かからプレゼントを一つもらう。
- 参加者は、自分と同じグループに属している人にはプレゼントをあげない。
- どのグループにも属さない人や、複数のグループに属する人はいない。
以下、perlでの素直な実装。
use strict;
use warnings;
sub px {
my $party = shift;
my ( %from, %to );
for my $to ( keys %$party ) {
my $group = $party->{$to};
my @candidates = grep {
$_ ne $to # not thyself
and $party->{$_} ne $group # not a member of thy group
and !$from{$_} # not received the present yet
} keys %$party;
return unless @candidates; # failure
my $from = $candidates[ int( rand(@candidates) ) ];
$to{$to} = $from;
$from{$from} = $to;
}
return \%to;
}
sub validate_party {
my $party = shift;
my %group;
$group{ $party->{$_} }++ for keys %$party;
my $total = scalar keys %$party;
while ( my ( $g, $us ) = each %group ) {
my $them = $total - $us;
die "invalid party :", " group $g ($us) has more people",
" than the total of the rest ($them)\n"
if $us > $them;
}
}
sub exchange_present{
my $party = shift;
validate_party($party);
my $result;
1 until $result = px($party);
$result;
}
local $\ = "\n";
use Data::Dumper;
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 0;
# my %party = map{ $_ => $_%5 } (0..99); # example of a large party
# my %party = ( foo => 'a', bar => 'b', quux => 'b' ); # invalid group
my %party = (
dan => 'parent',
naomi => 'parent',
hazumi => 'child',
kiwami => 'child',
);
print Dumper exchange_present( \%party );
この問題、一目見ればわかりますが、解なしの場合が存在することがすぐ分かります。例えば、2名がグループA、1名がグループBの時は、必ずグループAの人が1名誰にもプレゼントを渡せなくなってしまいます。ここから解が存在する条件は、「すべてのグループにおいて、そのグループの人数がその他のグループの人数の合計以下であること」となります。上記のプログラムは、それもちゃんと実装しています。
Happy Holidays!
Dan the Party Animal
このブログにコメントするにはログインが必要です。
さんログアウト
この記事には許可ユーザしかコメントができません。