题意:给出 n 条鱼, ,每条鱼有个属性值 xr,每条鱼可以选择另外一条它认为是雌性的鱼发起攻击,当鱼 i 攻击鱼 j 时,会产卵,且卵的属性值为 xr[i]^xr[j] ,每条鱼仅发起一次攻击,求最佳的攻击方案,使得产卵的总属性值最大,输出这个最大值;
分析:把一条鱼分成两个点,一个点代表攻击方,一个点代表被攻击方,那就是二分图了,预处理然后 跑一下 KM 求最大权匹配就可以了;
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN = 100+5;
const int INF = 0x3f3f3f3f;
int love[MAXN][MAXN];
int ex_girl[MAXN];
int ex_boy[MAXN];
bool vis_girl[MAXN];
bool vis_boy[MAXN];
int match[MAXN];
int slack[MAXN];
int N;
int xr[MAXN];
char mp[MAXN][MAXN];
bool dfs(int girl)
{
vis_girl[girl]=true;
for(int boy=0;boy<N;boy++)
{
if(vis_boy[boy]) continue;
int gap=ex_girl[girl]+ex_boy[boy]-love[girl][boy];
if(gap==0)
{
vis_boy[boy]=true;
if(match[boy]==-1||dfs(match[boy]))
{
match[boy]=girl;
return true;
}
}
else
{
slack[boy]=min(slack[boy],gap);
}
}
return false;
}
int KM()
{
memset(match,-1,sizeof(match));
memset(ex_boy,0,sizeof(ex_boy));
for(int i=0;i<N;i++)
{
ex_girl[i]=love[i][0];
for(int j=0;j<N;j++)
ex_girl[i]=max(ex_girl[i],love[i][j]);
}
for(int i=0;i<N;i++)
{
fill(slack,slack+N,INF);
while(1)
{
memset(vis_girl,false,sizeof(vis_girl));
memset(vis_boy,false,sizeof(vis_boy));
if(dfs(i)) break;
int d=INF;
for(int j=0;j<N;j++)
if(!vis_boy[j]) d=min(d,slack[j]);
for(int j=0;j<N;j++)
{
if(vis_girl[j]) ex_girl[j]-=d;
if(vis_boy[j])
ex_boy[j]+=d;
else
slack[j]-=d;
}
}
}
int res=0;
for(int i=0;i<N;i++)
{
res+=love[match[i]][i];
}
return res;
}
int main()
{
while(~scanf("%d",&N)&&N)
{
memset(love,0,sizeof(love));
for(int i=0;i<N;i++) scanf("%d",&xr[i]);
for(int i=0;i<N;i++) scanf("%s",mp[i]);
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
if(mp[i][j]=='1')
love[i][j]=xr[i]^xr[j];
printf("%d\n",KM());
}
return 0;
}