传送门:acdream 1227
有个国王有n个儿子要找对象,现在恰好有n个妹子跟他们配对,每个人都有自己中意的一至多个妹子(像话么!!),如果配对到中意的妹子则会有满意度,问怎么配对能使得总的满意度最大,输出配对方案,假如配对对象不中意则输出0,否则输出妹子的编号
红果果的最大权匹配,
二分图,儿子一边,妹子一边,每个儿子向所有妹子建边,若是中意的妹子,边权赋为满意度,然后套用km模板求出匹配方案即可
/******************************************************
* File Name: b.cpp
* Author: kojimai
* Creater Time:2014年10月05日 星期日 12时05分42秒
******************************************************/
//二分最大权匹配,并输出每个人的匹配对象,若匹配值为0,则输出0
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 405
int n,ans[FFF],love[FFF],linkx[FFF];
int len[FFF][FFF],sx[FFF],sy[FFF],lx[FFF],ly[FFF];
bool bfs(int i)
{
int j;
sx[i] = 1;
for(j = 1;j <= n;j++)
{
if(!sy[j]&&lx[i] + ly[j] == len[i][j])
{
sy[j] = 1;
if(!ans[j] || bfs(ans[j])){
linkx[i] = j;
ans[j] = i;
return true;
}
}
}
return false;
}
void km()
{
int i,j,d,x;
for(i = 1;i <= n;i++)
{
lx[i] = -1;
for(j = 1;j <= n;j++)
lx[i] = max(lx[i],len[i][j]);
}
memset(ly,0,sizeof(ly));
memset(ans,0,sizeof(ans));
for(x = 1;x <= n;x++) {
while(1){
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
if(bfs(x))break;
d = 23333333;
for(i = 1;i <= n;i++)
{
if(sx[i])
for(j = 1;j <= n;j++)
if(!sy[j])
d = min(d,lx[i]+ly[j]-len[i][j]);
}
for(i = 1;i <= n;i++)
if(sx[i]) lx[i] -= d;
for(j = 1;j <= n;j++)
if(sy[j]) ly[j] += d;
}
}
}
int main()
{
int k,x;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&love[i]);
memset(len,0,sizeof(len));
for(int i=1;i<=n;i++)
{
scanf("%d",&k);
while(k--)
{
scanf("%d",&x);
len[i][x] = love[i];
}
}
km();
for(int i = 1;i <= n;i++)
{
if(len[i][linkx[i]])
printf("%d",linkx[i]);
else
printf("%d",0);
if(i<n)
printf(" ");
else
printf("\n");
}
return 0;
}