稳定的婚姻问题
稳定婚姻问题指出,给定 N 个男人和 N 个女人,每个人按照偏好顺序对所有异性成员进行排名,将男人和女人一起结婚,这样就没有两个异性都愿意彼此比他们现在的合作伙伴。如果没有这样的人,所有的婚姻都是“稳定的”(来源维基)。
考虑以下示例。
假设有两个男人m1和m2以及两个女人w1和w2 。
让m1的偏好列表为 { w1 , w2 }
让m2的偏好列表为 { w1 , w2 }
让w1的偏好列表为 { m1 , m2 }
让w2的偏好列表为 { m1 , m2 }
匹配的 { { m1 , w2 }, { w1 , m2 } } 不稳定,因为m1和w1会更喜欢彼此而不是指定的伙伴。匹配的 { m1 , w1 } 和 { m2 , w2 } 是稳定的,因为没有两个异性会比他们指定的伴侣更喜欢彼此。
总是有可能从偏好列表中形成稳定的婚姻(见参考资料)。以下是寻找稳定匹配的Gale-Shapley 算法:
这个想法是在有任何可用的自由人时遍历所有自由人。每个自由人都会按照顺序去他偏好列表中的所有女性。对于他去的每个女人,他都会检查那个女人是否有空,如果有,他们都会订婚。如果女人不是自由的,那么女人选择要么对他说不,要么根据她的偏好列表放弃她目前的订婚。因此,如果一个女人有更好的选择,一次完成的订婚可能会被打破。 Gale-Shapley 算法的时间复杂度为 O(n 2 )。
以下是来自 Wiki 的完整算法
Initialize all men and women to free
while there exist a free man m who still has a woman w to propose to
{
w = m's highest ranked such woman to whom he has not yet proposed
if w is free
(m, w) become engaged
else some pair (m', w) already exists
if w prefers m to m'
(m, w) become engaged
m' becomes free
else
(m', w) remain engaged
}
输入和输出:输入是一个大小为 (2*N)*N 的二维矩阵,其中 N 是女性或男性的数量。从 0 到 N-1 的行代表男性的偏好列表,从 N 到 2*N – 1 的行代表女性的偏好列表。因此,男性的编号从 0 到 N-1,女性的编号从 N 到 2*N – 1。输出是已婚对的列表。
以下是上述算法的实现。
C++
// C++ program for stable marriage problem
#include
#include
#include
using namespace std;
// Number of Men or Women
#define N 4
// This function returns true if woman 'w' prefers man 'm1' over man 'm'
bool wPrefersM1OverM(int prefer[2*N][N], int w, int m, int m1)
{
// Check if w prefers m over her current engagement m1
for (int i = 0; i < N; i++)
{
// If m1 comes before m in list of w, then w prefers her
// current engagement, don't do anything
if (prefer[w][i] == m1)
return true;
// If m comes before m1 in w's list, then free her current
// engagement and engage her with m
if (prefer[w][i] == m)
return false;
}
}
// Prints stable matching for N boys and N girls. Boys are numbered as 0 to
// N-1. Girls are numbered as N to 2N-1.
void stableMarriage(int prefer[2*N][N])
{
// Stores partner of women. This is our output array that
// stores passing information. The value of wPartner[i]
// indicates the partner assigned to woman N+i. Note that
// the woman numbers between N and 2*N-1. The value -1
// indicates that (N+i)'th woman is free
int wPartner[N];
// An array to store availability of men. If mFree[i] is
// false, then man 'i' is free, otherwise engaged.
bool mFree[N];
// Initialize all men and women as free
memset(wPartner, -1, sizeof(wPartner));
memset(mFree, false, sizeof(mFree));
int freeCount = N;
// While there are free men
while (freeCount > 0)
{
// Pick the first free man (we could pick any)
int m;
for (m = 0; m < N; m++)
if (mFree[m] == false)
break;
// One by one go to all women according to m's preferences.
// Here m is the picked free man
for (int i = 0; i < N && mFree[m] == false; i++)
{
int w = prefer[m][i];
// The woman of preference is free, w and m become
// partners (Note that the partnership maybe changed
// later). So we can say they are engaged not married
if (wPartner[w-N] == -1)
{
wPartner[w-N] = m;
mFree[m] = true;
freeCount--;
}
else // If w is not free
{
// Find current engagement of w
int m1 = wPartner[w-N];
// If w prefers m over her current engagement m1,
// then break the engagement between w and m1 and
// engage m with w.
if (wPrefersM1OverM(prefer, w, m, m1) == false)
{
wPartner[w-N] = m;
mFree[m] = true;
mFree[m1] = false;
}
} // End of Else
} // End of the for loop that goes to all women in m's list
} // End of main while loop
// Print the solution
cout << "Woman Man" << endl;
for (int i = 0; i < N; i++)
cout << " " << i+N << "\t" << wPartner[i] << endl;
}
// Driver program to test above functions
int main()
{
int prefer[2*N][N] = { {7, 5, 6, 4},
{5, 4, 6, 7},
{4, 5, 6, 7},
{4, 5, 6, 7},
{0, 1, 2, 3},
{0, 1, 2, 3},
{0, 1, 2, 3},
{0, 1, 2, 3},
};
stableMarriage(prefer);
return 0;
}
Java
// Java program for stable marriage problem
import java.util.*;
class GFG
{
// Number of Men or Women
static int N = 4;
// This function returns true if woman
// 'w' prefers man 'm1' over man 'm'
static boolean wPrefersM1OverM(int prefer[][], int w,
int m, int m1)
{
// Check if w prefers m over
// her current engagement m1
for (int i = 0; i < N; i++)
{
// If m1 comes before m in list of w,
// then w prefers her current engagement,
// don't do anything
if (prefer[w][i] == m1)
return true;
// If m comes before m1 in w's list,
// then free her current engagement
// and engage her with m
if (prefer[w][i] == m)
return false;
}
return false;
}
// Prints stable matching for N boys and
// N girls. Boys are numbered as 0 to
// N-1. Girls are numbered as N to 2N-1.
static void stableMarriage(int prefer[][])
{
// Stores partner of women. This is our
// output array that stores passing information.
// The value of wPartner[i] indicates the partner
// assigned to woman N+i. Note that the woman
// numbers between N and 2*N-1. The value -1
// indicates that (N+i)'th woman is free
int wPartner[] = new int[N];
// An array to store availability of men.
// If mFree[i] is false, then man 'i' is
// free, otherwise engaged.
boolean mFree[] = new boolean[N];
// Initialize all men and women as free
Arrays.fill(wPartner, -1);
int freeCount = N;
// While there are free men
while (freeCount > 0)
{
// Pick the first free man
// (we could pick any)
int m;
for (m = 0; m < N; m++)
if (mFree[m] == false)
break;
// One by one go to all women
// according to m's preferences.
// Here m is the picked free man
for (int i = 0; i < N &&
mFree[m] == false; i++)
{
int w = prefer[m][i];
// The woman of preference is free,
// w and m become partners (Note that
// the partnership maybe changed later).
// So we can say they are engaged not married
if (wPartner[w - N] == -1)
{
wPartner[w - N] = m;
mFree[m] = true;
freeCount--;
}
else // If w is not free
{
// Find current engagement of w
int m1 = wPartner[w - N];
// If w prefers m over her current engagement m1,
// then break the engagement between w and m1 and
// engage m with w.
if (wPrefersM1OverM(prefer, w, m, m1) == false)
{
wPartner[w - N] = m;
mFree[m] = true;
mFree[m1] = false;
}
} // End of Else
} // End of the for loop that goes
// to all women in m's list
} // End of main while loop
// Print the solution
System.out.println("Woman Man");
for (int i = 0; i < N; i++)
{
System.out.print(" ");
System.out.println(i + N + " " +
wPartner[i]);
}
}
// Driver Code
public static void main(String[] args)
{
int prefer[][] = new int[][]{{7, 5, 6, 4},
{5, 4, 6, 7},
{4, 5, 6, 7},
{4, 5, 6, 7},
{0, 1, 2, 3},
{0, 1, 2, 3},
{0, 1, 2, 3},
{0, 1, 2, 3}};
stableMarriage(prefer);
}
}
// This code is contributed by Prerna Saini
Python3
# Python3 program for stable marriage problem
# Number of Men or Women
N = 4
# This function returns true if
# woman 'w' prefers man 'm1' over man 'm'
def wPrefersM1OverM(prefer, w, m, m1):
# Check if w prefers m over her
# current engagement m1
for i in range(N):
# If m1 comes before m in list of w,
# then w prefers her current engagement,
# don't do anything
if (prefer[w][i] == m1):
return True
# If m comes before m1 in w's list,
# then free her current engagement
# and engage her with m
if (prefer[w][i] == m):
return False
# Prints stable matching for N boys and N girls.
# Boys are numbered as 0 to N-1.
# Girls are numbered as N to 2N-1.
def stableMarriage(prefer):
# Stores partner of women. This is our output
# array that stores passing information.
# The value of wPartner[i] indicates the partner
# assigned to woman N+i. Note that the woman numbers
# between N and 2*N-1. The value -1 indicates
# that (N+i)'th woman is free
wPartner = [-1 for i in range(N)]
# An array to store availability of men.
# If mFree[i] is false, then man 'i' is free,
# otherwise engaged.
mFree = [False for i in range(N)]
freeCount = N
# While there are free men
while (freeCount > 0):
# Pick the first free man (we could pick any)
m = 0
while (m < N):
if (mFree[m] == False):
break
m += 1
# One by one go to all women according to
# m's preferences. Here m is the picked free man
i = 0
while i < N and mFree[m] == False:
w = prefer[m][i]
# The woman of preference is free,
# w and m become partners (Note that
# the partnership maybe changed later).
# So we can say they are engaged not married
if (wPartner[w - N] == -1):
wPartner[w - N] = m
mFree[m] = True
freeCount -= 1
else:
# If w is not free
# Find current engagement of w
m1 = wPartner[w - N]
# If w prefers m over her current engagement m1,
# then break the engagement between w and m1 and
# engage m with w.
if (wPrefersM1OverM(prefer, w, m, m1) == False):
wPartner[w - N] = m
mFree[m] = True
mFree[m1] = False
i += 1
# End of Else
# End of the for loop that goes
# to all women in m's list
# End of main while loop
# Print solution
print("Woman ", " Man")
for i in range(N):
print(i + N, "\t", wPartner[i])
# Driver Code
prefer = [[7, 5, 6, 4], [5, 4, 6, 7],
[4, 5, 6, 7], [4, 5, 6, 7],
[0, 1, 2, 3], [0, 1, 2, 3],
[0, 1, 2, 3], [0, 1, 2, 3]]
stableMarriage(prefer)
# This code is contributed by Mohit Kumar
C#
// C# program for stable marriage problem
using System;
using System.Collections.Generic;
class GFG
{
// Number of Men or Women
static int N = 4;
// This function returns true if woman
// 'w' prefers man 'm1' over man 'm'
static bool wPrefersM1OverM(int [,]prefer, int w,
int m, int m1)
{
// Check if w prefers m over
// her current engagement m1
for (int i = 0; i < N; i++)
{
// If m1 comes before m in list of w,
// then w prefers her current engagement,
// don't do anything
if (prefer[w, i] == m1)
return true;
// If m comes before m1 in w's list,
// then free her current engagement
// and engage her with m
if (prefer[w, i] == m)
return false;
}
return false;
}
// Prints stable matching for N boys and
// N girls. Boys are numbered as 0 to
// N-1. Girls are numbered as N to 2N-1.
static void stableMarriage(int [,]prefer)
{
// Stores partner of women. This is our
// output array that stores passing information.
// The value of wPartner[i] indicates the partner
// assigned to woman N+i. Note that the woman
// numbers between N and 2*N-1. The value -1
// indicates that (N+i)'th woman is free
int []wPartner = new int[N];
// An array to store availability of men.
// If mFree[i] is false, then man 'i' is
// free, otherwise engaged.
bool []mFree = new bool[N];
// Initialize all men and women as free
for (int i = 0; i < N; i++)
wPartner[i] = -1;
int freeCount = N;
// While there are free men
while (freeCount > 0)
{
// Pick the first free man
// (we could pick any)
int m;
for (m = 0; m < N; m++)
if (mFree[m] == false)
break;
// One by one go to all women
// according to m's preferences.
// Here m is the picked free man
for (int i = 0; i < N &&
mFree[m] == false; i++)
{
int w = prefer[m,i];
// The woman of preference is free,
// w and m become partners (Note that
// the partnership maybe changed later).
// So we can say they are engaged not married
if (wPartner[w - N] == -1)
{
wPartner[w - N] = m;
mFree[m] = true;
freeCount--;
}
else // If w is not free
{
// Find current engagement of w
int m1 = wPartner[w - N];
// If w prefers m over her current engagement m1,
// then break the engagement between w and m1 and
// engage m with w.
if (wPrefersM1OverM(prefer, w, m, m1) == false)
{
wPartner[w - N] = m;
mFree[m] = true;
mFree[m1] = false;
}
} // End of Else
} // End of the for loop that goes
// to all women in m's list
} // End of main while loop
// Print the solution
Console.WriteLine("Woman Man");
for (int i = 0; i < N; i++)
{
Console.Write(" ");
Console.WriteLine(i + N + " " +
wPartner[i]);
}
}
// Driver Code
public static void Main(String[] args)
{
int [,]prefer = new int[,]{{7, 5, 6, 4},
{5, 4, 6, 7},
{4, 5, 6, 7},
{4, 5, 6, 7},
{0, 1, 2, 3},
{0, 1, 2, 3},
{0, 1, 2, 3},
{0, 1, 2, 3}};
stableMarriage(prefer);
}
}
// This code is contributed by Rajput-Ji
Javascript
输出:
Woman Man
4 2
5 1
6 3
7 0