過半数とるまで、最下位の票を無効にしてもう一度投票し直しまっせっていう問題。
投票者は候補者をランク付けしておいて、一位の候補者が過半数を取っていればいいし、もしそうでなかったら、最下位に投票した投票者の票の次のランクの候補者に票を割り振っていくという。
シュワルツ変換でソートをかけていって、一位が過半数とってたらその候補者をreturnすればいいし、そうでなかったら、最下位候補者を投票の文字列から除いて再度やればいいのはわかったんだけど、 c++での書き方がわからん。
結局こんな感じになってしまった。一位と最下位調べるのにmapで組を作っておいて、イテレータで走査してminとmaxを記憶というやり方までは一緒。そのあと、最下位を消すのがわからなかったけど、この解答ではfindして見つかったindexをeraseしてた、なるほど。
perlだと
@votes = sort {$b->[1] <=> $a->[1]} map {[$_,$votes->{$_}]} split(//,$candidates);
っていうふうにつなげられるのがよいんだけどな。
$ballots = [map {s/$votes[-1]->[0]//;$_ } @$ballots];
あとCだと文字列の置換がまだしっくりこない。
perlの解答
sub outcome {
my ($candidates, $ballots) = @_;
my $total = @$ballots;
return "" if $total == 0;
my($votes, @votes);
while(1) {
$votes = count_vote($ballots);
@votes = sort {$b->[1] <=> $a->[1]} map {[$_,$votes->{$_}]} split(//,$candidates);
return $votes[0]->[0] if($votes[0]->[1] * 2 >= $total);
$ballots = [map {s/$votes[-1]->[0]//;$_ } @$ballots];
$candidates =~ s/$votes[-1]->[0]//;
}
}
sub count_vote {
my $ballots = shift;
my $counts = {};
$counts->{substr($_,0,1)}++ for (@$ballots);
return $counts;
}
print outcome("ABC",["ACB", "BCA", "ACB", "BCA", "CBA"]); # B
print outcome("DCBA",["ACBD", "ACBD", "ACBD", "BCAD", "BCAD", "DBCA", "CBDA"]); # B
print outcome("ACB",["ACB", "BCA", "ACB", "BCA", "ACB", "BCA", "CBA", "CAB"]); # ""
print outcome("CAB",["ACB", "BCA", "ACB", "BCA", "ACB", "BCA", "CAB", "CAB"]); # A
print outcome("Z",["Z"]); # Z