zoukankan      html  css  js  c++  java
  • UVALive 3989 Ladies' Choice(稳定婚姻问题:稳定匹配、合作博弈)

    题意:男女各n人,进行婚配,对于每个人来说,所有异性都存在优先次序,即最喜欢某人,其次喜欢某人...输出一个稳定婚配方案。所谓稳定,就是指未结婚的一对异性,彼此喜欢对方的程度都胜过自己的另一半,那么这对异性就有私奔的可能性。

    这里明显也是一个匹配问题,与最佳二分完美匹配所不同的是,二分匹配重在求最佳权值,而这里求的是满足彼此的要求。这里用到了Gale-Shapley算法。

    算法学习:http://wenku.baidu.com/view/964a503843323968011c92c3.html

         http://wenku.baidu.com/view/7aa841f2fab069dc502201cb.html

    前者描述详细,值得一看;后者虽然描述不够清晰,但给出了优劣势的证明,并且对第一篇文章倒数第三段提到的“欺诈与博弈”给出了具体样例,可以借鉴。

    先把代码贴出来,其实就是贪心的思路,模拟一下这种操作方式,O(n2)的复杂度,已经是输入复杂度了,不能再省了。

    uva挂了,所以不保证code的正确性。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<memory.h>
     4 using namespace std;
     5 #define Clear(f, nr) memset(f, nr, sizeof(f))
     6 const int SIZE = 1008;
     7 const int INF = 1 << 30;
     8 int n;
     9 int men[SIZE][SIZE], wmen[SIZE][SIZE];
    10 int menChs[SIZE];  //女生的选择
    11 int que[SIZE * SIZE];
    12 bool vis[SIZE][SIZE];
    13 void StableMarriage()
    14 {
    15  int front = 0, rear = 0;
    16  Clear(menChs, -1);
    17  Clear(vis, 0);
    18  for(int i = 1; i <= n; i ++)
    19   que[rear ++] = i;
    20 
    21  while(front < rear) {
    22   int tmp = que[front ++];
    23   for(int i = 1; i <= n; i ++) {
    24    if(!vis[tmp][wmen[tmp][i]]) {
    25     vis[tmp][wmen[tmp][i]] = 1;
    26     if(menChs[wmen[tmp][i]] == -1) {
    27      menChs[wmen[tmp][i]] = tmp;
    28      break;  //忘加一个break改了一个小时
    29     }
    30     else {
    31      int mark = menChs[wmen[tmp][i]];
    32      if(men[wmen[tmp][i]][mark] < men[wmen[tmp][i]][tmp]) {
    33       menChs[wmen[tmp][i]] = tmp;
    34       que[rear ++] = mark;
    35       break;
    36      }
    37     }
    38    }
    39   }
    40  }
    41 
    42  return ;
    43 }
    44 void Print()
    45 {
    46  for(int j = 1; j <= n; j ++)
    47   for(int i = 1; i <= n; i ++)
    48    if(menChs[i] == j)
    49     cout << i << endl;
    50 }
    51 int main()
    52 {
    53  int T, x;
    54  cin >> T;
    55  int gg = 0;
    56  while(T --) {
    57   if(gg ++) puts("");
    58   cin >> n;
    59   for(int i = 1; i <= n; i ++)
    60    for(int j = 1; j <= n; j ++)
    61     cin >> wmen[i][j];  //女生记邻接表
    62   for(int i = 1; i <= n; i ++)
    63    for(int j = 1; j <= n; j ++) {
    64     cin >> x;
    65     men[i][x] = n - j;  //男生记邻接阵 权值
    66    }
    67   StableMarriage();
    68   Print();
    69  }
    70 }
    View Code

    同样还是用自己的话描述一下:

      一、首先给出算法:依据优先次序,男生在第一轮分别向自己最喜欢的女生求婚,女生对于求婚,总是从中选择最理想的人选。一轮结束后,男生的结果是求婚成功或者被拒。第二轮,单身们继续追求真爱,向各自喜好的排在第二的人求婚(不管对方是否有男伴),女生同样是选择最理想的人选。这一轮结束后,男生的结果是求婚成功、被拒,又或是被其他男人抢走女伴,重新沦为单身。第三轮...直到不存在单身男子为止。

      二、为什么这样就能得到“稳定”的方案呢?

      在算法运行结束后,对于一对(x,y),男生x是按优先次序,从高到低向女生求婚,之前的女生都拒绝了他,才会与y成婚。假设仍存在不稳定,那么相比于y,会使男生x私奔的只有那些拒绝了x的女生,由算法可知,女生拒绝x的理由是她们有更优的人选,所以女生们没有理由跟x私奔,假设失败。所以Gale-Shapley算法一定能得到稳定方案。

      三、进一步讨论:优势问题。看似对男生残酷(不断地表白)的选择方式,其实最终得到的方案,是在稳定前提下,男生的最优方案。相对应的,对女生而言是最差的方案。

      “男生最优”其实不难理解,因为男生x是按优先顺序表白的,比成婚对象y更理想的女生都拒绝了x,理由是有了比x更好的x'。若是对男生而言,还存在更优方案,那么只能去“强迫”拒绝了x的女生y',组成(x,y')。可是对于x'而言,被x替换掉以后只能找不如y'的女生成婚了,不稳定也就出现了:(x',y')会私奔。所以不会有更优方案,原方案就是“男生最优”。

      “女生最劣”不好理解,不过可以仿照上述分析。对于女生而言,若还有更劣势的情况,只能是女生y还可能和不如x的男生x'成婚,组成(x',y),这里注意,那么x在被拒之后,只能去追求不如y的女生,不稳定也就出现了:(x,y)会私奔,所以不会有更劣方案,原方案已经是“女生最劣”。

      另一种抽象的解释:已知在稳定条件下,对于男生、女生,方案的优劣都有上下界。在方案未定之前,整个系统是不稳定的(仍有单身,说明跟别人抢老婆失败了= =)。男生逐渐降低自己的要求(逼近上界),主动出击,寻求最理想的真爱;女生被动接受,在选择她的众多男生中选择最佳(逼近下界)。当系统稳定(单身消失),男女生的选择分别是在稳定条件下的最优、最劣。(注意,女生最后的组合(x,y),虽然x不一定是最差的,但是比x好的都被其他女生抢走了,没能向y表白)

      优劣只是相对而言,交换顺序,就是女生主动、男生被动,最终方案就是“男生最劣”、“女生最优”。

      四、“欺诈与博弈”

      既然“女生最劣”,是不是可以有更优解呢?这就要欺诈。

      男        女

      1:BADC  A:1234

      2:ABCD  B:2143

      3:BCAD  C:3241

      4:ADBC  D:4231

      原本按照G-S算法,第一轮结束的结果是:(2,A),(1,B),3、4分别被B,A拒绝了;最终结果是(2,A)(1,B)(3,C)(4,D)。若A,B提前了解了每个人的优先序列,进行欺诈,在第一轮选择(4,A),(3,B),虽然A,B暂时配偶不理想,但是最终结果:(1,A)(2,B)(3,C)(4,D)对于女生而言是最优解。

      五、局限

      G-S算法的基础,是将数据分为两个集合(数量不一样,就不能依照“单身消失”这一条件结束,而应该判断全部单身男子是否访问完各自的优先序列),由一个集合主动,另一个被动。若集合数>2,就不存在绝对的主动、被动:x选择y,可能y去选择z。例如寝室分配,2n个人分n个寝室,每个人对其他(2n-1)人有喜恶,就不能用G-S算法解决。(想想看,若是在婚配问题上,就是说每个男生的优先序列上除了女生,还混进了(n-1)个男生...)事实上,它本身很可能不存在稳定方案,具体看第一篇文章的倒数第二段。

      六、拓展

      G-S算法中,后者“S”所表示的Shapley在2012年获得诺贝尔经济学奖,以下是相关介绍,主要研究算法部分。

      http://wenku.baidu.com/view/da999a2c4b35eefdc8d33354.html

      从第四页的“(二)稳定配置理论”开始(前面的经济术语恶心死了),介绍了两种合作博弈的算法:Gale-Sharpley算法和顶端交易循环算法。其中G-S算法除了“存在性”,“最优性”外,还介绍了“唯一性”:当且仅当男人的最优匹配和女人的最优匹配一致时,稳定条件下只包含唯一解。

      G-S算法用于解决“双边市场”的问题(男女各有所需),对于“单边市场”,即只有一侧存在需求(想象一下女生不会拒绝的情况),要用到“顶端交易循环算法”,例2中有详细介绍。(通俗来讲,都用到贪心的思想)

      首先明确“单边市场”下的稳定指的是什么:n个人选择n件物品,A选1,B选2,不会同时存在A更喜欢2,B更喜欢1,否则他们就可以交换(交易),即不稳定。

      给出算法:首先随意分配n件物品到n个人手中,随意选一个人,找到其优先序列中的第一件物品,观察该物品现在在谁手上,两个人之间构成有向边(纯粹是为了好表达才用有向边描述),重复建边过程,必然会产生一个环,环上的人通过彼此交换物品,可以实现每个人都获得最想要的物品。至此,一轮结束,环上的人及其物品不再考虑,其余人优先序列上去除这些物品。重复操作,直到所有人退出。

      为什么能成环就不用解释了,注意如果自己手上拿着的就是最想要的物品,构成自环,同样退出考虑范围。

      为什么这样就稳定呢?

      沿着算法的思路,第一轮退出的人不存在不稳定的可能,他们拿到了最理想的物品,没有人可以和他们交换。那么对于第一轮留下的全部人而言,第二轮退出的人不存在不稳定的可能,这些人要么拿到最理想的物品,要么拿到次理想的物品(最理想的物品被第一轮的人拿走了),第二轮留下的人不存在与这些人交换的可能。以此类推,方案稳定。

      例3、例4、例5都挺有意思,不过我认为真正要注意的不仅仅是分配的方法,还有判断不稳定的条件,什么是真正的公平我们不能一概而论,但如何能在某一方面实现相对公平才是要讨论的。就比如例4中提到的,五家合起来修路,若还不如两家合起来划算,为何还要五家一起。(例4让我又想到了电梯付费,是一个道理)

      还有一点疑问,就是文章中“罗斯对NRMP的重新设计,确保已婚医生夫妇也能实现稳定的匹配”。究竟是怎样的?是不是把夫妇二人缩成一个点就可以了?

  • 相关阅读:
    docker容器,镜像常用操作
    微信小程序登录状态
    微信小程序登录流程图
    GET和POST可传递的值到底有多大?
    php发送请求
    thinkphp 导入微信小程序加密解密库
    thinkphp 随机获取一条数据
    bootstrap row 行间距
    webstorm es6 语法报错
    Laravel
  • 原文地址:https://www.cnblogs.com/zstu-abc/p/3295514.html
Copyright © 2011-2022 走看看