线性规划 --圆桌问题

假期 2020.01.28

题目描述

有一个国际会议,很多国家需要参加,每一个国家的代表团的人数不一样,每一个会议桌可坐的人数也不一样,为了充分交流,同一个国家的不要做在同一桌上,设计算法实现最佳的座位安排方案。


思路解析

模型是网络问题,二分图匹配问题。与线性规划 --配对方案问题相似,参考请见该博文


代码解析

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define Max_size 1000
#define INF 0x7fffffff
int _floor[Max_size],_count[Max_size],pre_num[Max_size];
int current_num = 0;
struct Vertex {
	int first;
}vertex[Max_size];
struct Edge {
	int start;
	int next;
	int contain;
	int flow;
}edge[Max_size];
void add(int u, int v, int num);
void add_edge(int u,int v,int num);
void Print_flow(int m,int n);
void Print(int total);
void set_height(int start, int total);
int Isap(int start, int total, int point_total);
int main()
{
	int team_num, desk_num,num,sum = 0;
	cout << "请输入代表团数量与会议桌数量:";
	cin >> team_num >> desk_num;
	int total = team_num + desk_num;
	cout << "请输入每个代表团的数量:" << endl;
	memset(vertex, -1, sizeof(vertex));
	for (int i = 1; i <= team_num; i++){
		cin >> num;
		sum += num;
		add(0, i, num);
	}
	cout << "请输入每个会议桌可安排的最大人数:" << endl;
	for (int i = team_num + 1; i <= total; i++){
		cin >> num;
		add(i, total + 1, num);
	}
	for(int i = 1;i <= team_num;i++)//代表团到会议桌的连线
		for (int j = team_num + 1; j <= total; j++)
		{
			add(i, j, 1);
		}
	cout << endl;
	Print(total + 2);
	if (sum == Isap(0, total + 1, total + 2))
	{
		cout << "安排成功" << endl;
		Print_flow(team_num,desk_num);
		cout << endl;
		Print(total + 1);
	}
	else
		cout << "安排不成功" << endl;
	return 1;
}
void add(int u, int v, int num)
{
	add_edge(u, v, num);
	add_edge(v, u, num);
}
void add_edge(int u, int v, int num)
{
	edge[current_num].contain = num;
	edge[current_num].flow = 0;
	edge[current_num].start = v;
	edge[current_num].next = vertex[u].first;
	vertex[u].first = current_num++;
	return;
}
void set_height(int start, int total)
{
	queue<int> q;
	memset(_floor, -1, sizeof(_floor));
	memset(_count, 0, sizeof(_count));
	_floor[total] = 0;
	q.push(total);
	while (!q.empty())
	{
		int current = q.front();
		q.pop();
		++_count[_floor[current]];
		for (int i = vertex[current].first; i != -1; i = edge[i].next)
		{
			int u = edge[i].start;
			if (_floor[u] == -1)
			{
				_floor[u] = _floor[current] + 1;
				q.push(u);
			}
		}
	}
	cout << "初始化高度是:" << endl;
	cout << "_floor[ ] = ";
	for (int i = 1; i <= total; i++)
		cout << "  " << _floor[i];
	cout << endl;
	return;
}
int Isap(int start, int total, int point_total)
{
	set_height(start, point_total);
	int ans = 0, u = start;
	int d ;
	while (_floor[start] < point_total)
	{
		int v = vertex[u].first;
		if (u == start)
			d = INF;
		for (; v != -1; v = edge[v].next)
		{
			int point = edge[v].start;
			if (edge[v].flow < edge[v].contain && _floor[point] + 1 == _floor[u])
			{
				u = point;
				pre_num[point] = v;
				d = min(d, edge[v].contain - edge[v].flow);
				if (u == total)
				{
					cout << "增广路径是:" << total;
					while (u != start)//更新
					{
						int j = pre_num[u];
						edge[j].flow += d;
						edge[j + 1].flow -= d;
						u = edge[j + 1].start;
						cout << "--" << u;
					}
					cout << "增流:" << d << endl;
					ans += d;
					d = INF;
				}
				break;
			}
		}
		if (v == -1)
		{
			if (--_count[_floor[u]] == 0)
				break;
			int hmin = total;
			for (int j = vertex[u].first; j != -1; j = edge[j].next)
				if (edge[j].contain > edge[j].flow)
					hmin = min(hmin, _floor[edge[j].start]);
			_floor[u] = hmin + 1;
			cout << "重贴标签后的高度是:" << endl;
			cout << "_floor[ ] = ";
			for (int i = 1; i <= total; i++)
				cout << "  " << _floor[i];
			cout << endl;
			++_count[_floor[u]];
			if (u != start)//后退一步
				u = edge[pre_num[u] + 1].start;
		}
	}
	return ans;
}
void Print(int total)
{
	cout << "网络连接图如下:" << endl;
	for (int i = 0; i <= total; i++)
	{
		cout << "v" << i << "  [" << vertex[i].first;
		for (int j = vertex[i].first; j != -1; j = edge[j].next)
			cout << "] -- [" << edge[j].start << "  " << edge[j].contain << "  " << edge[j].flow << "  " << edge[j].next;
		cout << "]" << endl;
	}
	return;
}
void Print_flow(int m,int n)
{
	cout << "安排方案如下:" << endl;
	for (int i = 1; i <= m; i++)
	{
		cout << "第" << i << "代表团的会议桌: ";
		for (int j = vertex[i].first; j != -1; j = edge[j].next)
			if (edge[j].flow == 1)
				cout << edge[j].start - m << "  ";
		cout << endl;
	}
	return;
}

运行结果

在这里插入图片描述
在这里插入图片描述

发布了166 篇原创文章 · 获赞 45 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44116998/article/details/104099232
今日推荐