稳定匹配算法

一、题目

---- 输入:有1+2N行,第一行有两个数组N和K,N代表有N个男人和N个女人,K用于输出结果,接下来的N行为N个男人(编号为0到N-1)的优先级列表,如1 0 代表该男人的优先级中,woman1优先于woman0。再接下来的N行为N个女人人(编号同样为0到N-1)的优先级列表,如0 1代表该女人的优先级中man0优先于man1
---- 输出:应为一个数字,代表匹配完成后,编号为K的男人所匹配女人的编号

二、思路

自由人:即不在与异性约会的人
伪代码

三、优化

1、突破点

  1. 我们要能快速挑出一个自由人.
  2. 对一个男人m,我们要能够快速挑出他还没有求过婚的最高排名的女人
  3. 对—个女人w,我们要确定w当前是否有约会,如果是,我们要挑出她当前的伴侣.
  4. 对一个女人w和两个男人m与m‘,我们要能够再次在常数时间内确定,m和m’中谁的优先级更大

2、解决思路

与突破点一一对应

  1. 每次选的自由人要么是顺序选择之前没有约会过的,要么是上次被上个男生抢了约会机会的倒霉蛋。这样就避免寻找自由人。
  2. 因为男生都是按在他心中优先级由高到低的顺序来依次确定约会对象,所以可以确定下次约会对象的。nextwomen[i]:值为k时表示男生i下一次从女生k开始选伴侣,初始为0(优先级最高的女生)
  3. 使用match_women[i]:值为-1表示自由,值为k(k>=0)表示女生i当前正与男生k约会。
  4. 通过输入构造rankman[i][j]表示在女生i心中男生j的排名,便于快速比较两男生谁能和女生i约会

四、算法实现

  • match_man[i]:值为-1表示自由,值为k(k>=0)表示男生i当前正与女生k配对
  • man[i][j]表示男生i心中排名第j位的女生是man[i][j]
  • rankman[i][j]表示在女生i心中男生j的排名,便于快速比较两男生谁能和女生i约会
  • nextwomen[i]:值为k时表示男生i下一次从女生k开始选伴侣
import java.io.*;
import java.util.*;
class MyIO{
	StreamTokenizer input;
	PrintWriter output;
	public MyIO() {
		input=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		output=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	}
	int read() throws Exception {
		input.nextToken();
		return (int)input.nval;
	}
}
public class StableMatch {
	public static void main(String[] args) throws Exception{
		// TODO 自动生成的方法存根
		MyIO myIO =new MyIO();
		int n=myIO.read();
		int m=myIO.read();
		int[][] man=new int[n][n];
		int[][] rankman=new int[n][n];
		//赋初值
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				man[i][j]=myIO.read();
			}
		}
		for(int i=0;i<n;i++) {
			for(int j=0;j<n;j++) {
				int mani=myIO.read();
				rankman[i][mani]=j;//在第i号女生中mani男生的优先级是j
			}
		}
		int[] match_man=new int[n];
		int[] match_women=new int[n];
		int[] nextwomen=new int[n];//表示男生i下次与哪个优先级的女生约会
		//男女都未约会
		Arrays.fill(match_man, -1);
		Arrays.fill(match_women,-1);
		//求稳定匹配
		int nowindex=0,theboy=0;//nowindex是指男生nowindex之前的已经约会过了(但是有些可能现在是自由人)。theboy指当前正在遍历谁,theboy<=nowindex;
		while(nowindex<=n-1) {//如果0-m-1号男生都遍历完了,就退出
			boolean cannext=true;
			for(int i=nextwomen[theboy];i<n;i++) {
				int boy=theboy,girl=man[boy][i];
				if(match_women[girl]==-1) {//女生i未约会,直接约会
					nextwomen[boy]++;//男生下次从后一个女生开始选择
					match_women[girl]=boy;//女生约会boy
					match_man[boy]=girl;//男生配对的女生
					break;//记得break!
				}
				else {/女生已匹配男生lastboy,判断男生lastboy与男生boy在女生的优先级
					int lastboy=match_women[girl];
					if(rankman[i][boy]<rankman[i][lastboy]) {//序号小,优先级高于正在约会的男生
						nextwomen[boy]++;//男生下次从后一个女生开始选择
						match_women[girl]=boy;//女生约会boy
						match_man[boy]=girl;
						match_man[lastboy]=-1;//lastboy to be free;
						cannext=false;
						theboy=lastboy;//下次遍历这个变自由的男生,而不是nowindex+1
						break;//记得break!
					}
				}
			}
			if(cannext) {//没有产生新的自由人,则可以遍历下一个男生,否则继续遍历那个新产生的自由人
				nowindex++;
				theboy=nowindex;
			}
		}
		System.out.println(match_man[m]);
	}
}

样例:
4 3
3 1 2 0
1 0 2 3
0 1 2 3
0 1 2 3
0 1 2 3
0 1 2 3
0 1 2 3
0 1 2 3
输出:
2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值