稳定婚姻问题专题小结(二分图匹配 稳定婚姻问题--延迟拒绝算法(Gale-Shapley 算法))

先给出Gale-Shapley 算法思想:

while 存在男人m是自由的且还没对每个女人都求过婚

         选择这个男人m
       令w是m的优先表中还没求过婚的最高排名的女人
                  if w是自由的 
                       (m,w)变成约会状态
                  else w当前与m1约会
                if w更偏爱m1而不爱m
                           m保持自由
                else w更偏爱m而不爱m1
                      (m,w)变成约会状态
                      m1变成自由
               endif
               endif
    endwhile


下面看例题:

Link:http://acm.hdu.edu.cn/showproblem.php?pid=1435


Stable Match

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 336    Accepted Submission(s): 138
Special Judge


Problem Description
Network 公司的BOSS 说现在他们公司建立的信号发射站和接收站经常出现信号发送接收不稳定的问题,信号的稳定度被定义为发射点到接收点的距离,距离越大,越不稳定,所以发射点跟接收点在可能的情况下应越近越好.
BOSS给8600的任务就是::建立一个匹配表,使得一个发射点对应一个接收点,对于某一个发射点来说,它的接收点离它越近那么就会更稳定,同样对于接收点也是一样的情况. 匹配的目标是使得整个网络变得稳定。,对于某2个匹配,比如,( a ---- 1) ,(b----2) ,如果发射点a 离接收点2 比 1要近,而且2 也离 发射点a要比 b 近, 那么 a 就很有可能把信号发到 2中,我们就说这个搭配是不 稳定的。同样如果发射点b 离接收点1 比 2 要近,而且1 也离 发射点b要比 a 近 ,也会出现不稳定的情 况. 而且每个点都有一个容量值,如果对于一个发射点到2个接收点的距离一样的话,它将首先选择容量大的那个. 所以8600就是要建立一个稳定的匹配,使得每个一个信号发射点对应一个接收点,并且不会出现信号不稳定的情况.
8600苦思冥想也没什么进展,希望你能帮他解决这个难题.
 

Input
输入数据首先包含一个正整数N,N<=20表示测试实例的个数.每个实例首先是一个整C,C<=200表示有C个信号发射点和C个信号接收点. 接下来的C行表示 C个发射点的编号,容量和坐标,坐标为,x,y,z 3个实数(x,y,z ≥0).最后C行是C个接收点的编号,容量和坐标.
 

Output
输出建立稳定搭配后各个发射点和接收点的编号,每一行代表一个搭配,前一个整数为发射点的编号,后一个为对应的接收点的编号。如果有多种情况,输出其中一种即可.如果任务不可能完成的话,输出"Impossible".每个实例后请输出一个空行.
 

Sample Input
  
  
  
1 3 1 1 60.57 57.16 69.27 2 2 26.05 61.06 11.52 3 3 9.04 58.20 56.90 1 2 280.74 12.78 316.14 2 3 305.16 267.15 87.65 3 1 240.72 312.41 217.10
 

Sample Output
  
  
  
3 1 1 2 2 3
 

Author
8600
 

Source
 


AC code:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#define oo 0x13131313
using namespace std;
const int maxn=200+5; 
const double eps=1e-8;
int N;//总共多少对男女(发射点 接收点) 
struct point
{
	int c;//容量 
	double x,y,z;//坐标 
};
point S[maxn],E[maxn];//发射点 接收点
int ranks[maxn][maxn],ranke[maxn][maxn];//发射点对接收点的排名 接收点对发射点的排名
int man[maxn],woman[maxn];//man[i]表示男编号为i所匹配的女对象编号 ,woman[i]表示女编号为i所匹配的男对象编号 
int tempman[maxn];//tempman[i]表示男编号为i所匹配的临时女对象编号是自己原先对所有女孩排完序后第几喜欢
                  //(当前剩下的能选择的女孩中男孩所选择的自己最喜欢的那位女孩所有女孩中排第几) 
struct node//排序关键字 
{
	double dis;//距离 
	int c; //容量 
	int pos;//参加排序的点的编号 
	int r;//参加排序的点的排名 
}Rank[maxn];//排序数组 
double dist(point A,point B)
{
	return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z);  
}
void input()
{
	int id,c;
	double x,y,z;
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
	{
		scanf("%d%d%lf%lf%lf",&id,&c,&x,&y,&z);
		S[id].c=c;
		S[id].x=x;
		S[id].y=y;
		S[id].z=z;
	}
	for(int i=1;i<=N;i++)
	{
		scanf("%d%d%lf%lf%lf",&id,&c,&x,&y,&z);
		E[id].c=c;
		E[id].x=x;
		E[id].y=y;
		E[id].z=z;
	}
} 
bool cmp(node a,node b)//使排序数组的下标按距离、容量为第一和第二关键字进行排序 
{
	if(fabs(a.dis-b.dis)>eps)
		return a.dis<b.dis;
	else
		return a.c>b.c;
}
bool cmp2(node a,node b)//使排序数组的下标与点的编号对应 
{
	return a.pos<b.pos;
}
void countrank()
{
	for(int i=1;i<=N;i++)
	{
		memset(Rank,0,sizeof(Rank));
		for(int j=1;j<=N;j++)
		{
			Rank[j].c=E[j].c;
			Rank[j].dis=dist(S[i],E[j]);
			Rank[j].pos=j;
		}
		sort(Rank+1,Rank+N+1,cmp);//使排序数组的下标按距离、容量为第一和第二关键字进行排序
		for(int j=1;j<=N;j++)
		{
			ranks[i][j]=Rank[j].pos;//i追求的最合适第j个是谁
		}
	}
	for(int i=1;i<=N;i++)
	{
		memset(Rank,0,sizeof(Rank));
		for(int j=1;j<=N;j++)
		{
			Rank[j].c=S[j].c;
			Rank[j].dis=dist(E[i],S[j]);
			Rank[j].pos=j;
		}
		sort(Rank+1,Rank+N+1,cmp);//使排序数组的下标按距离、容量为第一和第二关键字进行排序
		for(int j=1;j<=N;j++)
		{
			Rank[j].r=j;//记录当前点j对排名 
		}
		sort(Rank+1,Rank+N+1,cmp2);//使排序数组的下标与点的编号对应 
		for(int j=1;j<=N;j++)
		{
			ranke[i][j]=Rank[j].r; //ranke i追求的j的排名; 
		}
	}
}
void GS()  
{
	int ok=1;
	memset(man,0,sizeof(man));//初始化男所匹配女对象编号为0,表示单身  
    memset(woman,0,sizeof(woman)); 
    for(int i=1;i<=N;i++)
    {
        tempman[i]=1;//初始化男孩只能选择的女孩是自己第一喜欢(最喜欢)的 
    }
    while(ok==1)  
    {
    	ok=0;
		for(int i=1;i<=N;i++)  //男生去求偶  
		{
			if(man[i]==0)//单身   
			{
				ok=1; 
				int womenpos=ranks[i][tempman[i]];//当前男孩最想要选的女孩编号
			 if(woman[womenpos]==0)//该女孩目前是单身,则暂时追求成功
			 {
			 	woman[womenpos]=i;//女孩接受该男孩,有了男对象i了,不为0,脱单
				man[i]=womenpos; //男孩暂时追求成功,不为0,脱单 
				tempman[i]++;//万一女孩抛弃了他,男孩失恋后下次求偶只能选择的女孩是自己第几喜欢的 
			 }
			  else if(ranke[womenpos][woman[womenpos]]>ranke[womenpos][i])//状态不稳定,因为这个女孩当前的男友不如现在追求她的男孩i好,
			  {														//女孩抛弃原来男友,与当前男孩匹配 
			  	man[woman[womenpos]]=0;//女孩的原先男友失恋了,被女孩抛弃,变为单身
				woman[womenpos]=i;//女孩接受该男孩,有了男对象i了,不为0,脱单
			    man[i]=womenpos;  //男孩暂时追求成功,不为0,脱单
		        tempman[i]++; //万一女孩抛弃了他,男孩失恋后下次求偶只能选择的女孩是自己第几喜欢的  
			  }  
			   else
			   {
			   		tempman[i]++;//男孩追求的这个第tempman[i]喜欢的女孩不成功,只能再继续选择相对“次喜欢”的  
			   } 
			}
		 } 
	} 
}
void output()  
{
 	 for(int i=1;i<=N;i++) 
 	 {
	  	printf("%d %d\n",woman[i],i);  
	 } 
} 
int main()
{
    //freopen("D:\in.txt","r",stdin);
	int T;
	cin>>T;
	while(T--)
    {
        input();
        countrank();
        GS();
        output();  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林下的码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值