關於穩定婚姻問題

其實這個東西比較好玩……

意義比較深遠……

尤其是對廣大屌絲和窮搓矮和魔法師而言……

這個問題在組合數學第9章出現

問的是:

n男n女,每個男的對每個女的有一個評分,每個女的對每個男的有一個評分,然後……

他們兩兩配對……

當然結婚以後有可能不幸福,所以希望找到一種配對方案,滿足

不存在這樣的一對(狗)男女,他們不在一起,同時對對方的評分比對自己配偶高……如果這樣他們就會私奔啊私奔~~~~


這個很明顯是二分圖,但是不是單純的二分圖……

有一個Gale-Shapley算法(應該是叫這兩個名字的兩個人提出的),又稱延遲認可算法

有兩種做法,一種男性最優,一種女性最優

以男性最優爲例:

①每一個男生向自己評分最高且沒拒絕過自己的女性求婚(有可能有女性獲得多個人的求婚)

②如果有女性獲得多個人的求婚(即使已經訂婚),那麼挑選自己評分最高的,與其訂婚,拒絕其他人

注意在②中,如果有女性已經訂婚,那麼她會比較訂婚的人和向自己提出請求的人,選擇評分高的那一個(這就是爲什麼是“訂婚”而非結婚)

算法的正確性隨便google一下就有

我想說的是爲什麼這個方案男性最優……一開始我也沒太弄清

這與我們平常的觀念不符——如果一個女生很受歡迎,那麼她更容易挑到自己滿意的人


但是有一點,有可能女生心儀的男生並不喜歡她,因此沒能向她求婚

舉個例子,有可能n個男生互相不是情敵,那麼第一輪求婚以後,算法就結束了,此時每個男生都心滿意足,而女生不一定……

然後接下來每次男生求婚都是挑的他覺得最好而且自己有機會的,而女生等啊等有可能都等不到想要的那個人……

而且需要注意的是穩定婚姻問題一定有解(就像屌絲最終會找到一個黑木耳……)



這給我們一個啓示……手快有手慢無,一定要主動啊主動~~~~


特別說明以上對基佬不適用……(說不定也適用??)


題目有POJ3487ZOJ1576NOJ1710(南開大學OJ……第一次聽說)

題目都差不多,都是裸的,輸入的處理可能麻煩點(ZOJMS最麻煩,得用map……雖然實際上也比較好寫)


POJ3487code:

//其實在處理被拒絕的男生的時候可以開隊列,應該可以加快速度,但是事後纔想起,就算了……反正數據範圍小……

//在處理字符這一點上自認爲寫的很醜……暴醜……其實可以把數組開大,就可以不用減'A'了,當時有點腦殘……

//Lib
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
using namespace std;
//Macro
#define rep(i,a,b) for(int i=a,tt=b;i<=tt;++i)
#define drep(i,a,b) for(int i=a,tt=b;i>=tt;--i)
#define erep(i,e,x) for(int i=x;i;i=e[i].next)
#define irep(i,x) for(__typedef(x.begin()) i=x.begin();i!=x.end();i++)
#define read() (strtol(ipos,&ipos,10))
#define sqr(x) ((x)*(x))
#define pb push_back
#define PS system("pause");
typedef long long ll;
typedef pair<int,int> pii;
const int oo=~0U>>1;
const double inf=1e20;
const double eps=1e-6;
string name="",in=".in",out=".out";
//Var
class P
{
public:
	bool exist;int married;
	int pri[60];
}person[60];
int n,pos[60],T;
void Init()
{
	memset(person,0,sizeof person);
	scanf("%d\n",&n);char ch,s[30];
	rep(i,1,n<<1)
		scanf("%c%*c",&ch),person[ch-'A'+1].exist=true;
	scanf("\n");
	rep(i,1,n)
	{
		scanf("%s",s+1);
		rep(i,3,strlen(s+1))
			person[s[1]-'A'+1].pri[i-2]=s[i]-'A'+1;
		pos[s[1]-'A'+1]=1;
	}
	rep(i,1,n)
	{
		scanf("%s",s+1);
		rep(i,3,strlen(s+1))
			person[s[1]-'A'+1].pri[s[i]-'A'+1]=i-2;
		person[s[1]-'A'+1].pri[0]=oo;
	}
}
void Set(int first,int second,int third)
{
	person[first].married=second;
	person[second].married=first;
	person[third].married=0;
}
void Work()
{
	int cnt=n;
	while(cnt)
	{
		rep(i,'a'-'A'+1,'z'-'A'+1)
		{
			if(person[i].exist&&!person[i].married)
			{
				int t=person[i].pri[pos[i]++];
				if(person[t].pri[i]<person[t].pri[person[t].married])
				{
					if(!person[t].married)cnt--;
					Set(t,i,person[t].married);
				}
			}
		}
	}
	rep(i,'a','z')
	{
		if(person[i-'A'+1].exist)
			printf("%c %c\n",i,person[i-'A'+1].married+'A'-1);
	}
}
int main()
{
//	freopen((name+in).c_str(),"r",stdin);
//	freopen((name+out).c_str(),"w",stdout);
	for(scanf("%d",&T);T;T--)
	{
		Init();
		Work();
		puts("");
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章