数据结构学习第13篇 - 回溯法解决婚姻匹配问题

回溯法与分支限界法

一、稳定婚姻问题(必做)

有n对男女要配成n对夫妇,其中第i位男士对第j位女士的爱恋程度为p[i][j],第i位女士对第j位男士的爱恋程度为q[i][j],显然p[i][j]不一定等于q[j][i]。将他们组成n对夫妇,如果存在这样一个男男士和女士,这两人不是夫妇,但他们互相喜欢的程度胜过对自己的配偶的喜爱,这样的n对夫妇称为不稳定婚姻。如果不存在这样的男士和女士,则称为稳定婚姻。请利用回溯法求解n对男女的所有稳定婚姻配对和最佳稳定婚姻配对(n对夫妇婚姻总体的满意程度:S= Σ p[i][i’] *q[i’][i]其中第i位男士的配偶为第i’位女士)。

注意: 1.假设p[i][j]q[i][j]的取值为0.3-1.0,值越大代表满意度越高。

   2.需描述回溯法算法思想(解空间、状态树、搜索方法、限界函数)

     3.严格按照回溯法的算法框架编写

二、0-1背包问题(2选1)

给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,如何选择才能使得物品的总价格最高?请利用优先队列式分支限界法求解该问题。

注意: 1、优先队列结构可以使用库函数

    2.需描述回溯法算法思想(解空间、状态树、搜索方法、限界函数)

      3.严格按照分支限界法的算法框架编写

三、N皇后问题(2选1)

在N*N的棋盘上放置彼此不受攻击的N个皇后。按照国际象棋的规则,皇后可以攻击与之处于同一行或同一列或同一斜线上的棋子。N皇后的问题等价于在N*N大小的棋盘中放置N个皇后,任何2个皇后都不放在同一行或同一列或同一斜线上。使用队列式分支限界法,求出N个皇后的一种放置方案。

1、队列结构可以使用库函数

2.需描述回溯法算法思想(解空间、状态树、搜索方法、限界函数)

3.严格按照分支限界法的算法框架编写


上机13  回溯法解决婚姻匹配文体

  • 回溯法
  1. 算法思想:
    可以使用回溯法解决婚姻匹配文题。具体如下:通过建立解空间树,以数的层次作第几个男士,以第几个枝丫作第几个女士。并且用递归的方式以深搜的方法探索各叶子节点。通过限界函数减去枝叶:
  1. 先该女士再此之前是否已经配对过,如果已经配对,返回上一层;如果没有配对,进入2。
  2. 判断已经配对的男女与新配对的男女是否存在稳定性。如果不稳定,放回上一层;如果稳定。把该新配对的男女存起来。

最后根据是否到达叶子节点为终止条件,如果到达叶子节点,返回上一层。利用公式计算:n对夫妇婚姻总体的满意程度:S= Σ p[i][i’] *q[i’][i]其中第i位男士的配偶为第i’位女士)计算出最为满意的一组。

 

2、实现代码及运行结果

程序源代码如下:

/*

------------------回溯法解决稳定婚姻问题-------------------------

*/

 

#include <iostream>

#include <cstring>

 

using namespace std;

 

#define MAXSIZE 30 //男女最大配对对数

 

double mlove[MAXSIZE][MAXSIZE]; //男喜欢女的程度数组

double wmlove[MAXSIZE][MAXSIZE]; //女喜欢男的程度数组

 

 

int n; //男女配对对数

 

int mo[MAXSIZE]; //存储配对男的数组

 

int s = -1;

 

double sum[MAXSIZE];

 

int b = -1;

 

int a = 0;

 

 

 

//记录每组男女配对总和

void love_sum(void)

{

b++;

for (int i = 0; i < n; i++)

{

sum[b] = sum[b] + mlove[i][mo[i]] * wmlove[mo[i]][i];

}

cout << "该组男女配对爱的总和是:" << sum[b] << endl << endl;

 

}

 

void cout_best(void)

{

int max = 0;

for (int i = 0; i <= b; i++)

{

if (max < sum[i])

{

max = sum[i];

}

}

cout << "最优男女配对情况是:第" << max+1 << "组数据" << endl;

}

 

 

void output(void)

{

a++;

cout <<"第" << a << "组男女配对情况是:" << endl;

for (int i = 0; i < n; i++)

{

cout << "第" << i+1 << "男子配对第" << mo[i]+1 << "个女子" << endl;

}

love_sum();

}

 

//参数 k:第几个男士    参数 t:第几个女士

int limit(int k,int t)

{

//判断女生是否已经配对

for (int i = 0; i < k; i++)

{

if (t == mo[i])

{

return 0; //不稳定

}

}

 

//判断男女配对是否稳定

for (int i = 0; i < k; i++)

{

if ((wmlove[t][i] > wmlove[t][k] && mlove[i][t] > mlove[i][mo[i]]) || (wmlove[mo[i]][k] > wmlove[mo[i]][i] && mlove[k][mo[i]] > mlove[k][t]))

{

return 0; //不稳定

}

}

return 1; //稳定

}

 

void backtrack(int t)

{

if(t == n)

{

output();

return;

}

for(int i = 0; i < n; i++)

{

 

if(limit(t, i))

{

mo[t] = i;

backtrack(t+1);

}

}

}

 

int main()

{

//初始化数组

memset(mlove, 0, sizeof(int)*MAXSIZE*MAXSIZE);

memset(wmlove, 0, sizeof(int)*MAXSIZE*MAXSIZE);

memset(mo, 255, sizeof(int)*MAXSIZE);

memset(sum, 0, sizeof(int)*MAXSIZE);

 

cout << "请输入男女配对对数:________\b\b\b\b\b";

cin >> n;

 

int t;

 

cout << "请输入男生对女生的喜爱程度" << endl;

for(int i = 0; i < n; i++)

{

for(int j = 0; j < n; j++)

{

cin >> mlove[i][j];

}

}

 

cout << "请输入女生对男生的喜爱程度" << endl;

for(int i = 0; i < n; i++)

{

for(int j = 0; j < n; j++)

{

cin >> wmlove[i][j];

}

}

backtrack(0);

cout_best();

system("pause");

return 0;

}

实现结果:

  1. 当输入结果男女配对个数为3,

男生对女生的喜爱程度是:

(列表示男生,行表示女生)

0.6 0.7 0.5

0.7 0.8 0.9

0.9 0.8 0.7

女生对男生的喜爱程度是:

(列表示女生,行表示男生)

0.4 0.6 0.5

0.5 0.7 0.8

0.7 0.6 0.5

达到预期结果

  1. 当输入结果男女配对对数是:2

男生对女生的喜爱程度是:

(列表示男生,行表示女生)

0.1  0.3

0.2  0.4

女生对男生的喜爱程度是:

(列表示女生,行表示男生)

0.2  0.3

0.3  0.5

达到预期结果

3、复杂度分析及算法改进

1时间复杂度

算法中,给n对男女稳定婚姻配对,主要耗费时间的是解空间树,解空间是排列树,耗费的时间是o(n!);而遍历每个结点都需要通过限界函数判断,限界函数的耗费的时间是o(n)。

总的时间复杂度是

T(n)= o(n!) * o(n)。

所以T(n)= o(n*n!)

  1. 空间复杂度

算法中,耗费空间的是存储男女喜欢程度的二维数组,耗费空间是o(n^2)和解空间树耗费的空间o(n^2)

所以s(n)= o(n^2).

(3)算法改进

目前想不到改进方法

猜你喜欢

转载自blog.csdn.net/guanshanyue96/article/details/89008697
今日推荐