假期 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;
}
运行结果