📜  稳定的婚姻问题

📅  最后修改于: 2022-05-13 01:57:54.304000             🧑  作者: Mango

稳定的婚姻问题

稳定婚姻问题指出,给定 N 个男人和 N 个女人,每个人按照偏好顺序对所有异性成员进行排名,将男人和女人一起结婚,这样就没有两个异性都愿意彼此比他们现在的合作伙伴。如果没有这样的人,所有的婚姻都是“稳定的”(来源维基)。

考虑以下示例。
假设有两个男人m1m2以及两个女人w1w2
m1的偏好列表为 { w1 , w2 }
m2的偏好列表为 { w1 , w2 }
w1的偏好列表为 { m1 , m2 }
w2的偏好列表为 { m1 , m2 }
匹配的 { { m1 , w2 }, { w1 , m2 } } 不稳定,因为m1w1会更喜欢彼此而不是指定的伙伴。匹配的 { 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