题目:http://codevs.cn/problem/1028/
思路:KM算法求解
题解:
/* 1028 花店橱窗布置 */
#include <stdio.h>
#define MAXN 101
#define max(X,Y) ((X>Y)?X:Y)
#define min(X,Y) ((X<Y)?X:Y)
#define INF 2147483647
int F, V; /* 花束数,花瓶数 */
int aesthetics[MAXN][MAXN]; /* 花束-花瓶美学值对应表 */
int linky[MAXN], visx[MAXN], visy[MAXN], lack;
int lx[MAXN] = {0}, ly[MAXN] = {0};
int maxans; /* 最大美学值 */
/* 匈牙利算法 */
int find(int x)
{
int y;
int t;
/* 标记花束x已访问 */
visx[x] = 1;
for(y = 1; y <= V; y++)
{
/* 如果花瓶y已使用,继续下一次循环 */
if(1 == visy[y])
{
continue;
}
/* 计算是否匹配 */
t = lx[x] + ly[y] - aesthetics[x][y];
if(0 == t)
{
visy[y] = 1;
if(0 == linky[y] || 1 == find(linky[y]))
{
linky[y] = x;
return 1;
}
}
else
{
lack = min(lack, t);
}
}
return 0;
}
/* KM算法 */
void km()
{
int fi, vi, i;
/* 初始化链接关系 */
for(vi = 1; vi <= V; vi++)
{
linky[vi] = 0;
}
/* 初始化花束顶标值 */
for(fi = 1; fi <= F; fi++)
{
for(vi = 1; vi <= V; vi++)
{
lx[fi] = max(lx[fi], aesthetics[fi][vi]);
}
}
/* 初始化花瓶顶标值 */
for(vi = 1; vi <= V; vi++)
{
ly[vi] = 0;
}
/* 求完备匹配 */
for(fi = 1; fi <= F; fi++)
{
for(;;)
{
/* 清零访问标记 */
for(i = 1; i <= V; i++)
{
visx[i] = 0;
visy[i] = 0;
}
lack = INF;
if(1 == find(fi))
{
break;
}
/* 修改已访问点顶标值 */
for(i = 1; i <= V; i++)
{
if(1 == visx[i])
{
lx[i] = lx[i] - lack;
}
if(1 == visy[i])
{
ly[i] = ly[i] + lack;
}
}
}
}
/* 测试 - 打印顶标值及对应表 */
/*
printf("花瓶-花束对应表:\n");
for(vi = 1; vi <= V; vi++)
{
if(0 != linky[vi])
{
printf("V[%2d](%2d) -> F[%2d](%2d)\n", vi, ly[vi], linky[vi], lx[linky[vi]]);
}
}
*/
/******************/
}
/* 主函数入口 */
int main()
{
int fi, vi; /* 索引值 */
/* 打开数据文件 */
FILE *fp;
if(NULL == (fp = fopen("data.txt", "r")))
{
return 1;
}
/***************/
/* 获取花束数,花瓶数 */
fscanf(fp, "%d %d", &F, &V);
/* 获取对应美学值 */
for(fi = 1; fi <= F; fi++)
{
for(vi = 1; vi <= V; vi++)
{
fscanf(fp, "%d", &aesthetics[fi][vi]);
}
}
km();
maxans = 0;
for(vi = 1; vi <= V; vi++)
{
maxans = maxans + aesthetics[linky[vi]][vi];
}
/* 打印结果 */
printf("%d", maxans);
/* 关闭数据文件 */
fclose(fp);
/****************/
return 0;
}