poj3487稳定婚姻匹配

      稳定婚姻问题:有n位男士和n位女士,每一个人都对每个异性有一个喜好度的排序,代表对他的喜爱程度,现在希望给每个男士找一个女士作配偶,使得每人恰好有一个异性配偶。如果男士u和女士v不是配偶但喜欢对方的程度都大于喜欢各自当前配偶的程度,则称他们为一个不稳定对。稳定婚姻问题就是希望找出一个不包含不稳定对的方案。
       算法非常简单,称为求婚-拒绝算法,每位男士按照自己喜欢程度从高到低依次给每位女士主动求婚直到有一个女士接受他,对于每个女士,如果当前向她求婚的配偶比她现有的配偶好则抛弃当前配偶,否则不予理睬,循环往复直到所有人都有配偶。有趣的是,看起来是女士更有选择权,但是实际上最后的结果是男士最优的(man-optimal)。
     首先说明最后匹配的稳定性,随着算法的执行,每位女士的配偶越来越好,而每位男士的配偶越来越差。因此假设男士u和女士v形成不稳定对,u一定曾经向v求过婚,但被拒绝。这说明v当时的配偶比u更好,因此算法结束后的配偶一定仍比u好,和不稳定对的定义矛盾,类似的,方式我们考虑最后一个被抛弃的男士和抛弃这位男士的女士,不难得出这个算法一定终止的结论。
       如果存在一个稳定匹配使得男士i和女士j配对,则称(i,j)是稳定对。对于每个男士i,设所有稳定对(i,j)中i 最喜欢的女士为best(i),则可以证明这里给出的算法对让每位男士i与best(i)配对。对于所有男士来说,不会有比这更好的结果了,而对于女士则恰恰相反,对于她们来说不会有比这更糟的结果了,因此这个算法是男士最优的。
      算法一定得到稳定匹配,并且复杂度显然是O(n^2),因为每个男士最多考虑每个女士一次,考虑的时间复杂度是O(1),当然了,需要作一定的预处理得到这个复杂度。

import java.util.Arrays;
import java.util.Scanner;

public class stablemarry3487 {
	class boy {
		int stack[] = new int[27], top;
		int match;
		int get() {
			return stack[top++];
		}
	}
	class girl {
		int rank[] = new int[27], id;
		int stack[] = new int[30], top;
		void insert(int k) {
			stack[top++] = k;
		}
		void match() {
			if (top ==0)
				return;
			 //在所有向自己求婚的男生中选择最喜欢的一个
			int min = 99, idx = -1;
			for (int i = 0; i < top; i++)
				if (rank[stack[i]] < min) {
					idx = stack[i];
					min = rank[idx];
				}
			// 将其他男生加入单身队列
			for (int i = 0; i < top; i++)
				if (idx != stack[i])
					queue[tail++] = stack[i];
			//通知选择的男生匹配成功并保存到备选队列中
			bb[idx].match = id;
			top = 1;
			stack[0]=idx;
		}
	}
	Scanner scan = new Scanner(System.in);
	int queue[] = new int[30], head, tail, n;
	boy bb[] = new boy[30];
	girl gg[] = new girl[30];

	void init() {
		n = scan.nextInt();
		head = tail = 0;
		Arrays.fill(bb, null);
		Arrays.fill(gg, null);
		for (int i = 0; i < n; i++) {
			String s = scan.next();
			queue[tail++] = s.charAt(0) - 'a';
		}
		for (int i = 0; i < n; i++)
			scan.next();
		for (int i = 1; i <= n; i++) {
			String s = scan.next();
			int k = s.charAt(0) - 'a';
			bb[k] = new boy();
			for (int j = 0; j < n; j++)
				bb[k].stack[j] = s.charAt(j + 2) - 'A';
		}
		for (int i = 0; i < n; i++) {
			String s = scan.next();
			int k = s.charAt(0) - 'A';
			gg[k] = new girl();
			gg[k].id = k;
			for (int j = 0; j < n; j++)
				gg[k].rank[s.charAt(j + 2) - 'a'] = j;
		}
	}

	void work() {
		while (head != tail) {
			//单身男性向没有拒绝自己且最喜欢的女生求婚
			for (int i = head; i < tail; i++) {
				int k = queue[i];
				int p = bb[k].get();
				gg[p].insert(k);
			}
			head = tail = 0;			
			for (int i = 0; i < 26; i++)
				if (gg[i] != null)
					gg[i].match();//女生在想自己求婚的男生中选择最喜欢的并把其他的添加到队列中
		}
		for (int i = 0; i < 26; i++)
			if (bb[i] != null)
				System.out.println((char) ('a' + i) + " "
						+ (char) ('A' + bb[i].match));

	}

	void run() {
		int cas = scan.nextInt();
		while (cas-- > 0) {
			init();
			work();
			System.out.println();
		}
	}
	public static void main(String[] args) {
		new stablemarry3487().run();
	}
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值