题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2813
我的链接:http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=17728#problem/L
算法思想:二分图的最优匹配求最小权覆盖,吕布的战将为集合一(二分图的行),曹操的战将为集合二(二分图的列),如果两边的战将间有战争就连边,建图。
然后直接套模板即可。
题目的关键是如何输入且存储两边的战将名字,这里用到了C++中STL的map容器,水过了。PS:大牛说字典树最快。
STL的map:
头文件#include<map>
#include<string>
using namespace std;
建立容器:map<string,int> m1;
map<string,int> m2;
清空容器:m1.clear();
m2.clear();
进入容器:if(mi[a]==0) m1[a]=k1++; (PS :之前k1要初始化,至于是0还是1就看你自己的模板了)
或者if(mi.find(a)==m1.end()) m1[a]=k1++;也一样。
One fihgt one
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1665 Accepted Submission(s): 543
![](https://i-blog.csdnimg.cn/blog_migrate/ce5d79d01672ea1f6e3033648b6bd2be.jpeg)
There’s little time , but Lv Bu is unaware of how to arrange his warriors , what he know is that he have n brave generals while Cao Cao has m , and he has k fights to choose from , he’d like to make all his n warriors participate in the battle but get the least injuries . Lv Bu is happy because there is always a good solution . So , now is your task to tell Lv Bu the least injuries his troop would get.
No one could take part in two fights.
The next k lines are the information about k possible fights , for each line are two strings (no more than 20 characters ) and an integer. The first string indicates Lv Bu’s general and the second , of course , Cao Cao’s , and the integer is the injury Lv Bu’s general would get if this fight were chosen.
2 3 5 LvBu ZhangFei 6 LvBu GuanYu 5 LvBu XuChu 4 ZhangLiao ZhangFei 8 ZhangLiao XuChu 3
8
另外要注意的就是不能直接套用以前的N*N的模板了,中间相应的地方注意自己改成m,看来有必要重写模板了啊!
//Accepted 496 KB 734 ms C++ 1967 B
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<iostream>
using namespace std;
map<string,int> m1;
map<string,int> m2;
const int maxn=210;
int w[maxn][maxn];
bool s[maxn],t[maxn];
int lx[maxn],ly[maxn];
int match[maxn];
int n,m,k;
bool hungary(int u){
s[u]=true;
for(int v=1;v<=m;v++){
if(!t[v] && lx[u]+ly[v]==w[u][v]){
t[v]=true;//易遗忘
if(match[v]==-1 || hungary(match[v])){
match[v]=u;
return true;
}
}
}
return false;
}
int KM(){
int ans=0;
memset(match,-1,sizeof(match));
for(int i=1;i<=n;i++){
lx[i]=-1<<30;//注意
}
memset(ly,0,sizeof(ly));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
lx[i]=max(lx[i],w[i][j]);
for(int i=1;i<=n;i++){
while(1){
memset(s,false,sizeof(s));
memset(t,false,sizeof(t));
if(hungary(i)) break;
else{
int a=1<<30;
for(int j=1;j<=n;j++) if(s[j]){
for(int k=1;k<=m;k++) if(!t[k] && a>lx[j]+ly[k]-w[j][k])
a=lx[j]+ly[k]-w[j][k];
}
for(int j=1;j<=n;j++){
if(s[j]) lx[j]-=a;
}
for(int j=1;j<=m;j++){
if(t[j]) ly[j]+=a;
}
}
}
}
for(int i=1;i<=m;i++) if(match[i]!=-1)//
ans+=w[match[i]][i];
return -ans;//易遗忘
}
int main(){
char name1[21],name2[21];
int u,v,injury;
while(scanf("%d%d%d",&n,&m,&k)!=EOF){
m1.clear();
m2.clear();
u=v=1;
for(int i=1;i<=n;i++){//不要忘了初始化图,因为此题不一定会填满n*m的边
for(int j=1;j<=m;j++)
w[i][j]=-1<<30;
}
while(k--){
scanf("%s%s%d",name1,name2,&injury);
if(m1.find(name1)==m1.end()) m1[name1]=u++;//若战将没有入图
if(m2.find(name2)==m2.end()) m2[name2]=v++;
w[m1[name1]][m2[name2]]=-injury;
}
printf("%d\n",KM());
}
return 0;
}