#include <cstdio>
#include <memory.h>
#include <algorithm> // 使用其中的 min 函数
using namespace std;
const int MAX = 405;
int n; // X 的大小
int weight [MAX] [MAX]; // X 到 Y 的映射(权重)
int lx [MAX], ly [MAX],a[MAX],ans[MAX]; // 标号
bool sx [MAX], sy [MAX]; // 是否被搜索过
int match [MAX]; // Y(i) 与 X(match [i]) 匹配
// 初始化权重
void init (int size);
// 从 X(u) 寻找增广道路,找到则返回 true
bool path (int u);
// 参数 maxsum 为 true ,返回最大权匹配,否则最小权匹配
int bestmatch (bool maxsum = true);
void init (int size)
{
// 根据实际情况,添加代码以初始化
n = size;
int i,j,k,t;
memset(weight,0,sizeof(weight));
for (i=1;i<=n;i++) scanf("%d",&a[i-1]);
for (i=0;i<n;i++)
{
scanf("%d",&k);
for (j=0;j<k;j++)
{
scanf("%d",&t);
weight[i][t-1]=a[i]*a[i];
}
}
}
bool path (int u)
{
sx [u] = true;
for (int v = 0; v < n; v ++)
if (!sy [v] && lx[u] + ly [v] == weight [u] [v])
{
sy [v] = true;
if (match [v] == -1 || path (match [v]))
{
match [v] = u;
return true;
}
}
return false;
}
int bestmatch (bool maxsum)
{
int i, j;
if (!maxsum)
{
for (i = 0; i < n; i ++)
for (j = 0; j < n; j ++)
weight [i] [j] = -weight [i] [j];
}
// 初始化标号
for (i = 0; i < n; i ++)
{
lx [i] = -0x1FFFFFFF;
ly [i] = 0;
for (j = 0; j < n; j ++)
if (lx [i] < weight [i] [j])
lx [i] = weight [i] [j];
}
memset (match, -1, sizeof (match));
for (int u = 0; u < n; u ++)
while (1)
{
memset (sx, 0, sizeof (sx));
memset (sy, 0, sizeof (sy));
if (path (u))
break;
// 修改标号
int dx = 0x7FFFFFFF;
for (i = 0; i < n; i ++)
if (sx [i])
for (j = 0; j < n; j ++)
if(!sy [j])
dx = 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;
}
}
int 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]; // 如果需要保持 weight [ ] [ ] 原来的值,这里需要将其还原
}
return sum;
}
int main()
{
int n,i;
scanf ("%d", &n);
init (n);
int cost = bestmatch (true);
//printf ("%d\n", cost);
//for (i=0;i<n;i++) printf("%d ",match[i]+1);
for (i=0;i<n;i++)
if (weight[match[i]][i]==0) ans[match[i]]=0;else
ans[match[i]]=i+1;
for (i=0;i<n-1;i++) printf("%d ",ans[i]);
printf("%d",ans[n-1]);
return 0;
}
二分图带权匹配
最新推荐文章于 2022-11-30 22:12:48 发布