稳定婚姻系统 学习笔记

题意

原题是关于男女配对婚姻的,但是由于这个背景敏感,可能会由于表述不够客观而挑起性别对立,于是将题面进行更加合理公正,尊重人权的更改。

现在有 \(n\) 个生理性别为男性,性别认同亦为男性,性倾向为女性的人,以及有 \(n\) 个生理性别为女性,性别认同为女性,性倾向为男性的人

现在有 \(n\) 个红点和 \(n\) 个蓝点(请注意:这里的红点蓝点并非隐喻或暗指向上文的男性和女性),第 \(i\) 个红点匹配第 \(j\) 个蓝点的权值为 \(a(i,j)\)。你需要求出一种匹配方案,将男性和蓝点两两匹配,使得不存在两组匹配 \((p,x),(q,y)\),使得 \(a(p,x)<a(p,y)\)\(a(q,y)<a(q,x)\),(\(p,q\) 是红点,且 \(x,y\) 是蓝点)。

解法

我们采用贪心算法来解决这个与性别无关的问题。

我们枚举每一个红点 \(p\),并按照权值从大到小第枚举它可以匹配的蓝点 \(x\)。如果枚举到的蓝点没有与其它红点形成匹配,那么就让红点与此蓝点匹配即可。

否则,假设此蓝点已经婚姻的红点为 \(q\)。那么比较 \(a(p,x),a(q,y)\),如果 \(a(p,x)>a(q,y)\) 那么就让此蓝点匹配上 \(p\),而让 \(q\) 按照上述方法重新寻找匹配即可。

容易发现,此算法复杂度是 \(O(n^2)\) 的。

例题

https://lightoj.com/problem/employment

本题就将性别问题非常合理地转化成了公司雇人问题。代码如下,虽然是 Wreng Answer

#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x;i<=y;++i)
#define per(i,x,y) for(int i=x;i>=y;--i)
#define lon long long
using namespace std;
const int n7=204;
int T,n,a[n7][n7],rk[n7][n7],vis[n7],que[n7*n7],head,tail;

int rd(){
	int shu=0;bool fu=0;char ch=getchar();
	while( !isdigit(ch) ){if(ch=='-')fu=1;ch=getchar();}
	while( isdigit(ch) )shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar();
	return fu?-shu:shu;
}

int main(){
	T=rd();
	rep(TT,1,T){
		n=rd();
		rep(i,1,n+n)rep(j,1,n)a[i][j]=rd(),rk[i][ a[i][j] ]=j;
		memset(vis,0,sizeof vis);
		head=1,tail=n;
		rep(i,1,n)que[i]=i;
		while(head<=tail){
			int o=que[head];head++;
			rep(j,1,n){
				int yo=a[o][j];
				if(!vis[yo]){vis[yo]=o;break;}
				else{
					int yo=a[o][j],z=vis[yo];
					if(rk[yo][z]>rk[yo][o]){vis[yo]=o,tail++,que[tail]=z;}
				}
			}
		}
		printf("Case %d:",TT);
		rep(i,n+1,n+n){
			printf("(%d %d)",vis[i],i);
			if(i<n+n)putchar(' ');
		}
		if(TT<T)putchar('\n');
	}
	return 0;
}

posted @ 2022-03-17 18:49  BlankAo  阅读(124)  评论(0编辑  收藏  举报