题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2813
解题思路:
二分图最优匹配。map+KM,好像最优的算法应该是字典树+KM。不过还是过了。。。。700+ms
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
#define N 210
#define MAX 1 << 28
#define CLR(arr, what) memset(arr, what, sizeof(arr))
int res[N][N];
int lx[N], ly[N], slack[N];
bool visitx[N], visity[N];
int match[N];
int n, m, k;
bool Hungary(int u)
{
int temp;
visitx[u] = true;
for(int i = 1; i <= m; ++i)
{
if(visity[i])
continue;
temp = lx[u] + ly[i] - res[u][i];
if(temp == 0) //相等子图
{
visity[i] = true;
if(match[i] == -1 || Hungary(match[i]))
{
match[i] = u;
return true;
}
}
else
slack[i] = min(slack[i], temp);
}
return false;
}
void KM_Perfect_Match()
{
int temp;
CLR(lx, 0);
CLR(ly, 0);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
lx[i] = max(lx[i], res[i][j]);
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
slack[j] = MAX;
while(1)
{
CLR(visitx, false);
CLR(visity, false);
if(Hungary(i))
break;
else
{
temp = MAX;
for(int j = 1; j <= m; ++j)
if(!visity[j])
temp = min(temp, slack[j]);
if(temp == MAX)
return ;
for(int j = 1; j <= n; ++j)
if(visitx[j])
lx[j] -= temp;
for(int j = 1; j <= m; ++j)
if(visity[j])
ly[j] += temp;
else
slack[j] -= temp;
}
}
}
}
int main()
{
map<string, int> l;
map<string, int> c;
char lv[25], cao[25];
int injury, num1, num2;
int result;
while(~scanf("%d%d%d", &n, &m, &k))
{
num1 = num2 = 1;
result = 0;
CLR(match, -1);
CLR(res, 0);
l.clear(); c.clear();
for(int i = 0; i < k; ++i)
{
scanf("%s%s%d", lv, cao, &injury);
if(!l[lv])
l[lv] = num1++;
if(!c[cao])
c[cao] = num2++;
res[l[lv]][c[cao]] = 9999 - injury;
}
KM_Perfect_Match();
for(int i = 1; i <= m; ++i)
if(match[i] != - 1)
result += res[match[i]][i];
printf("%d\n", 9999 * n - result);
}
return 0;
}