km算法示例

11 篇文章 0 订阅
#include <memory.h>
#include <iostream>
#include <limits.h>
#include <float.h>
#include <math.h>

//#define min(a, b) ((a) < (b))? (a):(b)
#define PRECISON 0.0000001
#define DOUBLE_MIN(a, b) (((a) - (b)) < PRECISON)? (a):(b)

static const int MAX = 1024;
static int n = 1;
// X 到 Y 的映射(权重)
/*double weight[MAX][MAX] = {{3.1,  4.1,  6.00001,  4.0009,  9.0002,  7.0001,  19.1,  40.01,  22.09,  11.007},
						{6,  4,  5,  3, 8,   10, 13,  19,  17,  7 },
						{7,  5,  3,  4, 2,   8,  1,   6,   9,   10},
						{6,  3,  2,  2, 5,   99, 22,  44,  66,  9 },
						{8,  4,  5,  4, 7,   8,  23,  17,  15,  14},
						{1,  2,  4,  5, 34,  3,  9,   10,  27,  53},
     					{9,  3,  33, 32,19,  7,  43,  97,  2,   11},
						{2,  34, 9,  43,22,  13, 19,  37,  61,  10},
						{3,  90, 122,34,87,  95, 56,  98,  35,  77},
						{45, 23, 9,  7, 5,   32, 5,   28,  43,  17}
};*/
double weight[MAX][MAX] = 
{{    50.500000,     81.500000,    218.500000,    368.000000,    519.500000,    811.500000,    696.000000,   1360.000000,   1201.000000,   1336.000000,   1757.500000,   2063.500000,   2171.500000,   2190.000000,   2265.000000,   1519.500000,   1900.000000,   1931.500000,   2080.500000,   2140.500000,   2338.500000,   1974.500000},
{    195.500000,     65.500000,     72.500000,    223.000000,    373.500000,    666.500000,    550.000000,   1215.000000,   1056.000000,   1191.000000,   1612.500000,   1918.500000,   2026.500000,   2045.000000,   2120.000000,   1373.500000,   1754.000000,   1785.500000,   1934.500000,   1994.500000,   2192.500000,   1828.500000},
{    316.000000,    188.000000,     50.000000,    107.500000,    258.000000,    551.000000,    433.500000,   1099.500000,    940.500000,   1075.500000,   1497.000000,   1803.000000,   1911.000000,   1929.500000,   2004.500000,   1251.000000,   1631.500000,   1663.000000,   1812.000000,   1872.000000,   2070.000000,   1713.000000},
{    498.500000,    369.500000,    231.500000,     94.000000,     70.500000,    363.500000,    246.000000,    912.000000,    753.000000,    888.000000,   1309.500000,   1615.500000,   1723.500000,   1742.000000,   1817.000000,   1069.500000,   1450.000000,   1481.500000,   1630.500000,   1690.500000,   1888.500000,   1525.500000},
{    773.000000,    641.000000,    506.000000,    354.500000,    204.000000,     89.000000,    192.500000,    637.500000,    478.500000,    613.500000,   1035.000000,   1341.000000,   1449.000000,   1467.500000,   1542.500000,   1016.000000,   1396.500000,   1428.000000,   1577.000000,   1637.000000,   1835.000000,   1471.000000},
{    707.000000,    579.000000,    441.000000,    303.500000,    140.000000,    167.000000,     37.500000,    703.500000,    544.500000,    679.500000,   1101.000000,   1407.000000,   1515.000000,   1533.500000,   1608.500000,    860.000000,   1240.500000,   1272.000000,   1421.000000,   1481.000000,   1679.000000,   1317.000000},
{   1378.000000,   1246.000000,   1111.000000,    959.500000,    809.000000,    516.000000,    633.500000,     36.500000,    326.500000,    462.500000,    884.000000,   1190.000000,   1206.000000,   1314.500000,   1390.500000,   1374.000000,   1754.500000,   1786.000000,   1935.000000,   1995.000000,   2193.000000,   1829.000000},
{   1214.000000,   1082.000000,    947.000000,    795.500000,    645.000000,    352.000000,    469.500000,    254.500000,     37.500000,    172.500000,    594.000000,    900.000000,   1008.000000,   1026.500000,   1101.500000,   1083.000000,   1463.500000,   1495.000000,   1644.000000,   1704.000000,   1902.000000,   1538.000000},
{   1382.000000,   1250.000000,   1115.000000,    963.500000,    813.000000,    520.000000,    637.500000,    421.500000,    131.500000,      4.500000,    426.000000,    732.000000,    840.000000,    858.500000,    933.500000,    916.000000,   1296.500000,   1328.000000,   1477.000000,   1537.000000,   1735.000000,   1371.000000},
{   1671.500000,   1539.500000,   1404.500000,   1253.000000,   1102.500000,    809.500000,    927.000000,    711.000000,    421.000000,    285.000000,    136.500000,    442.500000,    550.500000,    569.000000,    644.000000,    833.500000,   1007.000000,   1038.500000,   1187.500000,   1247.500000,   1445.500000,   1081.500000},
{   1946.500000,   1814.500000,   1679.500000,   1528.000000,   1377.500000,   1084.500000,   1202.000000,    986.000000,    696.000000,    560.000000,    138.500000,    167.500000,    275.500000,    294.000000,    369.000000,   1108.500000,    761.000000,    763.500000,    912.500000,    972.500000,   1170.500000,    806.500000},
{   2158.000000,   2026.000000,   1891.000000,   1739.500000,   1589.000000,   1296.000000,   1413.500000,   1198.500000,    908.500000,    772.500000,    351.000000,     45.000000,     64.000000,     82.500000,    157.500000,   1320.000000,    972.500000,    908.000000,    892.000000,    760.000000,    958.000000,    594.000000},
{   2233.000000,   2101.000000,   1966.000000,   1814.500000,   1664.000000,   1371.000000,   1488.500000,   1273.500000,    983.500000,    847.500000,    426.000000,    120.000000,    104.000000,      7.500000,     82.500000,   1395.000000,   1047.500000,    983.000000,    967.000000,    773.000000,    883.000000,    519.000000},
{   2307.500000,   2175.500000,   2040.500000,   1889.000000,   1738.500000,   1445.500000,   1563.000000,   1345.000000,   1056.000000,    921.000000,    499.500000,    193.500000,    175.500000,     67.000000,      9.000000,   1469.500000,   1122.000000,   1057.500000,   1041.500000,    847.500000,    811.500000,    447.500000},
{   2511.500000,   2379.500000,   2244.500000,   2093.000000,   1942.500000,   1649.500000,   1767.000000,   1221.000000,   1260.000000,   1125.000000,    703.500000,    397.500000,    289.500000,    271.000000,    196.000000,   1673.500000,   1326.000000,   1261.500000,   1245.500000,   1051.500000,    995.500000,    571.500000},
{   2384.500000,   2252.500000,   2117.500000,   1966.000000,   1815.500000,   1522.500000,   1640.000000,   1424.000000,   1134.000000,    998.000000,    576.500000,    270.500000,    254.500000,    146.000000,     70.000000,   1546.500000,   1199.000000,   1134.500000,   1118.500000,    924.500000,    868.500000,    368.500000},
{   1320.000000,   1192.000000,   1054.000000,    916.500000,    753.000000,    780.000000,    576.500000,   1090.500000,    800.500000,    795.500000,   1217.000000,   1523.000000,   1631.000000,   1649.500000,   1724.500000,    247.000000,    627.500000,    659.000000,    808.000000,    869.000000,   1066.000000,   1433.000000},
{   1626.500000,   1498.500000,   1360.500000,   1223.000000,   1059.500000,   1086.500000,    883.000000,   1397.000000,   1107.000000,    971.000000,    911.500000,   1217.500000,   1325.500000,   1344.000000,   1419.000000,     59.500000,    321.000000,    353.500000,    501.500000,    563.500000,    759.500000,   1127.500000},
{   1996.000000,   1868.000000,   1730.000000,   1592.500000,   1429.000000,   1456.000000,   1252.500000,   1766.500000,   1476.500000,   1340.500000,    919.000000,    848.000000,    956.000000,    974.500000,   1049.500000,    429.000000,     80.500000,     17.000000,    132.000000,    194.000000,    390.000000,    758.000000},
{   2302.500000,   2174.500000,   2036.500000,   1899.000000,   1735.500000,   1762.500000,   1559.000000,   2073.000000,   1783.000000,   1647.000000,   1225.500000,    919.500000,    903.500000,    795.000000,    742.000000,    735.500000,    388.000000,    323.500000,    307.500000,    114.500000,     83.500000,    450.500000},
{   2079.500000,   1947.500000,   1812.500000,   1671.000000,   1510.500000,   1534.500000,   1335.000000,   1845.000000,   1555.000000,   1419.000000,    997.500000,    691.500000,    675.500000,    567.000000,    491.000000,   1241.500000,    894.000000,    829.500000,    813.500000,    619.500000,    563.500000,     55.500000},
{      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000,      0.000000}};

/*
double lx [MAX], ly [MAX]; 		// 标号
bool sx [MAX], sy [MAX]; 	// 是否被搜索过
int match [MAX]; 		// Y(i) 与 X(match [i]) 匹配
*/

bool path (int u, bool  *sx, bool *sy, double *lx, double *ly, int *match, double weight[][MAX], int n);
double bestmatch (bool *sx, bool *sy, double *lx, double *ly, int *match, double weight[][MAX], int n, bool maxsum); //maxsum = true表示找权值之和最大的,maxsum = false,表示找					 //权值之和最小的

using namespace std;

int main(void)
{

	double *lx = NULL, *ly = NULL;
	bool *sx = NULL, *sy = NULL; 
	double sum;
	int i, *match = NULL, n = 50;

	//if(NULL == (rows = (int *)malloc(sizeof(int) * n))) goto clear;
	//if(NULL == (cols = (int *)malloc(sizeof(int) * n))) goto clear;
	if(NULL == (match = (int *)malloc(sizeof(int) * n))) goto clear;
	if(NULL == (lx = (double *)malloc(sizeof(double) * n))) goto clear;
	if(NULL == (ly = (double *)malloc(sizeof(double) * n))) goto clear;
	if(NULL == (sx = (bool *)malloc(sizeof(bool) * n))) goto clear;
	if(NULL == (sy = (bool *)malloc(sizeof(bool) * n))) goto clear;

	memset(match, 0, sizeof(match[0]) * n);
	memset(lx, 0, sizeof(lx[0]) * n);
	memset(ly, 0, sizeof(ly[0]) * n);
	memset(sx, false, sizeof(sx[0]) * n);
	memset(sy, false, sizeof(sy[0]) * n);

	for(n = 43; n < 50; n++)
	{
		double cost = bestmatch(sx, sy, lx, ly, match, weight, n, true); //此时求的是最大权值之和,保存在cost中
		cout<<"max cost: "<<cost<<endl;

		for (i = 0; i < n; i++)	//输出顶点集u中的顶点
		{
			cout<<match[i]<<"  ";		
		}
		cout<<endl;

		for (i = 0; i < n; i++)  	//输出顶点集v中与u中”对应的”(一种最优的对应)的顶点集
		{
			cout<<i<<"  ";
		}
		cout<<endl;

		for (i = 0; i < n; i++)	//输出匹配的每队顶点之间的权值	
		{
			cout<<weight[match[i]][i]<<"  ";
		}
		cout<<endl;

		//int bestmatch (int *sx, int *sy, int *lx, int *ly, int *match, int **weight, int n, bool maxsum)
		cost = bestmatch(sx, sy, lx, ly, match, weight, n, false);	//此时求的是最大权值之和,保存在cost中
		cout<<"min cost: "<<cost<<endl;

		for (i = 0; i < n; i++)		//输出顶点集u中的顶点
		{
			cout<<match[i]<<"  ";
		}
		cout<<endl;

		for (i = 0; i < n; i++)	//输出顶点集v中与u中”对应的”(一种最优的对应)的顶点集
		{
			cout<<i<<"  ";		
		}
		cout<<endl;

		for (i = 0; i < n; i++)  	//输出匹配的每队顶点之间的权值
		{
			cout<<weight[match[i]][i]<<"  ";
		}
		cout<<endl;
		getchar();
	}
	
clear:
	free(match);
	free(lx);
	free(ly);
	free(sx);
	free(sy);

	return 0;
}

//unsigned long counts = 0;
bool path (int u, bool *sx, bool *sy, double *lx, double *ly, int *match, double weight[][MAX], int n)	//匈牙利递归算法找一个最大的匹配,但并没有找出最小覆盖,结果保存在
{	//printf("path %ld ", ++counts);		//match[]数组中,比如找到了最大匹配是5,则V中的顶点0 1 2 3 4依次对应
	sx[u] = true;  //U中的match[0] match[1] match[2] match[3] match[4]。注意左边顶点集u,右			//边为顶点集V
	for (int v = 0; v < n; v++)
	{
		if (!sy[v] && fabs(lx[u] + ly[v] - weight[u][v]) < PRECISON)
		{
			sy[v] = true;
			if (match[v] == -1 || path(match[v], sx, sy, lx, ly, match, weight, n))
			{
				match[v] = u;
				return true;
			}
		}
	}

	return false;
}

double bestmatch (bool *sx, bool *sy, double *lx, double *ly, int *match, double weight[][MAX], int n, bool maxsum)	 //这个算法就是km算法,权值之和最小或者最大的最大匹配(本程//序中的案列针对完全二分图的,最大匹配也是完全匹配,否则要对二分图做一定的处理,使之存在完美匹配的情形(一般完全二分图))
{
	int i, j;

	if (!maxsum)
	{
		for (i = 0; i < n; i++)
		{
			for (j = 0; j < n; j++)
			{
				weight[i][j] = -weight[i][j];
				//printf("%d ", weight[i][j]);
				//getchar();
			}

			//printf("\n");
		}
	}

	for (i = 0; i < n; i++)
	{
		lx[i] = weight[i][0];
	}

	for (i = 0; i < n; i++)
	{
		for (j = 1; j < n; j++)
		{
			if (lx[i] - weight[i][j] < PRECISON)
			{
				lx[i] = weight[i][j];
			}
		}
	}

	memset(match, -1, sizeof(match[0]) * n);
	for (int u = 0; u < n; u++)
	{
		while(1)
		{
			memset(sx, false, sizeof(sx[0]) * n);
			memset(sy, false, sizeof(sy[0]) * n);

			//bool path (int u, int *sx, int *sy, int *lx, int *ly, int *match, int **weight, int n)
			if (path(u, sx, sy, lx, ly, match, weight, n))
			{
				//printf("%d ", u);
				break;
			}

			double dx = DBL_MAX;
			for (i = 0; i < n; i++)
			{
				if (sx[i])
				{
					for (j = 0; j < n; j++)
					{
						if (!sy[j])
						{
							dx = DOUBLE_MIN(lx[i] + ly[j] - weight[i][j], dx);
						}
					}
				}
			}

			for (i = 0; i < n; i++)
			{
				if (sx[i])
				{
					lx[i] -= dx;
				}

				if (sy[i])
				{
					ly[i] += dx;
				}
			}
		}
	}

	double sum = 0;
	for (i = 0; i < n; i++)
	{
		sum += weight[match[i]][i];
	}

	if (!maxsum)
	{
		sum = -sum;
		for (i = 0; i < n; i++)
		{
			for (j = 0; j < n; j++)
			{
				weight[i][j] = -weight[i][j];
			}
		}
	}

	return sum;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值