Language:
The Stable Marriage Problem
Description 稳定婚姻系统问题如下
如果没有(m, f) , f ∈ F,m ∈ M f对m比对她的配偶中意的同时m对f比对他的配偶更加中意,那这个婚姻是‘稳定’的.如果一个稳定配对不存在另一个稳定婚姻配对,其中所有的男性的配偶都比现在强,那么这个稳定配对称为男性最优配对。 Input 第一行为数据数. 对于每组数据,第一行为n (0 < n < 27).接下来一行依次为男性的名字(小写字母)和女性的名字(大写字母)接下来 n 行为每个男性的中意程度名单(从大到小),接下来n行是女性的中意程度名单(同上). Output 输出一组男性最优配对,男性按字典序从小到大排列,每行为“男性名 女姓名”的形式; 每数据后输出一空行。 Sample Input 2 3 a b c A B C a:BAC b:BAC c:ACB A:acb B:bac C:cab 3 a b c A B C a:ABC b:ABC c:BCA A:bac B:acb C:abc Sample Output a A b B c C a B b A c C Source |
这题是很经典的稳定婚姻系统问题,它的解法为“求婚-拒绝”算法:
======================================================================================================
稳定婚姻问题的经典算法为求婚-拒绝算法(propose-and-reject algorithm),即
男士按自己喜欢程度从高到低依次给每位女士主动求婚,直到有一个接受他。女士每
次遇到比当前配偶更差的男士时拒绝他,遇到更喜欢的男士时就接受他,并抛弃以前
的配偶。被抛弃的男士继续按照列表向剩下的女士依次求婚,直到所有人都有配偶。
看起来女士更有选择权,但实际上最后得到的结果是男士最优(man-optimal)的。下
面我们详细描述这一算法并证明相应的结论。
如果算法最后得到了一个匹配,那么它一定是稳定的。为了证明这一点,我们首
先注意到随着算法的执行,每位女士的配偶越来越好,而每位男士的配偶越来越差。
因此假设男士u和女士v形成不稳定对,u一定曾经向v求过婚,但被拒绝。这说明v当时
的配偶比u更好,因此算法结束后的配偶一定仍比u好,和不稳定对的定义矛盾。
下面我们只需要说明算法一定成功结束,即不会存在一位男士u,使得他向所有
女士求婚后仍为单身。假设存在这样的人,设其中最后一次被抛弃时刻最晚的男士
为u,则他最后一次被抛弃时无配偶,因此当时一定存在女士v也没有配偶。由于v是单
身的,所以一定没有人向她求过婚,因此v还在u的考虑范围之中,以后会向v求婚。到
432 图论问题和算法
时u会再次有配偶,要么还将被抛弃一次,要么最后不会单身,无论哪种情况都将产生
矛盾。
这样,我们证明了算法一定得到稳定匹配。时间复杂度显然是O(n2),因此每个男
士最多考虑每个女士各一次,每次的时间复杂度均为O(1)。显然这已经是时间复杂度
的下限了,因为输入是O(n2)的。
如果存在一个稳定匹配使得男士i和女士j配对,则称(i,j)是稳定对。对于每个男
士i,设所有稳定对(i,j)中i 最喜欢的女士为best(i),则可以证明这里给出的算法对让每
位男士i与best(i)配对。对于所有男士来说,不会有比这更好的结果了,而对于女士则
恰恰相反——对于她们来说不会有比这更糟的结果了。
=================================================================================================================
Program p3487;
const
maxn=26;
var
tt,n,i,j,k:longint;
nam:array[1..2,1..maxn] of char;
female_like:array['A'..'Z','a'..'z'] of longint;
male_like:array['a'..'z',1..maxn] of char;
a:array['a'..'z'] of char;
b:array['A'..'Z'] of char;
s:string;
c:char;
q:array[1..maxn*maxn] of char;
h,t:longint;
now,v:char;
begin
readln(tt);
while (tt>0) do
begin
fillchar(a,sizeof(a),' ');
fillchar(b,sizeof(b),' ');
readln(n);
for k:=1 to 2 do
for i:=1 to n do
begin
read(nam[k,i]);
read(c);
end;
readln;
for i:=1 to n do
begin
readln(s);
for j:=3 to length(s) do male_like[s[1],j-2]:=s[j];
end;
for i:=1 to n do
begin
readln(s);
for j:=3 to length(s) do female_like[s[1],s[j]]:=n+1-(j-2);
end;
h:=1;t:=n;
for i:=1 to n do q[i]:=nam[1,i];
while h<=t do
begin
now:=q[h];
for i:=1 to n do
begin
v:=male_like[now,i];
if (b[v]=' ') then
begin
a[now]:=v;
b[v]:=now;
break;
end;
if (female_like[v,b[v]]<female_like[v,now]) then
begin
inc(t);
q[t]:=b[v];
a[b[v]]:=' ';
a[now]:=v;
b[v]:=now;
break;
end;
end;
inc(h);
end;
for now:='a' to 'z' do if a[now]<>' ' then writeln(now,' ',a[now]);
writeln;
dec(tt);
end;
end.