题意:吕布有 n 个武将 对战 曹操 m 个武将 (n<=m),并给出 k 个对战的战力损耗值,求吕布方的最优战对匹配,使得战力损耗值最小,只能一对一;(吕布的每个武将都必须战斗一场)
分析:KM匹配裸题,武将名字用 map 标序就行了;
代码:
#include<map>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN = 200+2;
const int INF = 0X3F3F3F3F3F;
int love[MAXN][MAXN];
int ex_girl[MAXN];
int ex_boy[MAXN];
bool vis_girl[MAXN];
bool vis_boy[MAXN];
int match[MAXN];
int ans[MAXN];
int slack[MAXN];
int n,N,e;
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;
ans[girl]=boy;
return true;
}
}
else
{
slack[boy]=min(slack[boy],gap);
}
}
return false;
}
int KM(int tot)
{
memset(ans,-1,sizeof(ans));
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<tot;i++) res+=love[i][ans[i]];
return res;
}
int main()
{
ios::sync_with_stdio(false);
map<string,int>ft,sd;
while(cin>>n>>N>>e)
{
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
love[i][j]=-INF;
ft.clear();
sd.clear();
string a,b;
int num,pre=0,suf=0;
while(e--)
{
cin>>a>>b>>num;
if(ft[a]==0) ft[a]=(++pre);
if(sd[b]==0) sd[b]=(++suf);
love[ft[a]-1][sd[b]-1]=-num;
}
cout<<-KM(n)<<'\n';
}
}