原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1498
题意:一个n*n的矩阵,矩阵的每个格子放一个气球,气球颜色最多50种,编号1---50。对于每种颜色的气球,每次消去一行或者一列的该种颜色气球,问k次操作后,该颜色气球是否还存留,如果存留输出该气球编号。多种颜色气球存留的话,按编号大小升序输出;一个都不存在输出-1。
别人的题解都是最小点覆盖,我没看出来,但是单从匈牙利算法出发,这题还是可以理解的。一个巧妙之处就是match数组的作用,对于当前颜色,消去当前行,发现match[ 列坐标]!=-1的时候,说明该列存有相同颜色气球,那么如果if (dfs(match[v], color))成立,我们就要删除该列,而不是行,这是个转化问题,感觉好菜啊,,,继续努力吧。
#define _CRT_SECURE_NO_DEPRECATE
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define INF 99999999;
using namespace std;
int n, k;
int a[105][105];
bool color[55];//该颜色是否存在
int match[105];
bool vis[105];
int dfs(int u, int color)
{
for (int v = 0; v < n; v++)
{
if (a[u][v] == color&&!vis[v])
{
vis[v] = true;
if (match[v] == -1 || dfs(match[v], color))
{
match[v] = u;
return 1;
}
}
}
return 0;
}
int hungarian(int color)
{
int ans = 0;
memset(match, -1, sizeof(match));
for (int i = 0; i < n; i++)
{
memset(vis, 0, sizeof(vis));
ans += dfs(i, color);
}
return ans;
}
int main()
{
while (scanf("%d%d", &n, &k), n || k)
{
memset(color, 0, sizeof(color));
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
scanf("%d", &a[i][j]);
color[a[i][j]] = 1;
}
}
int p[55];//保存不能k次消除完的点
int tol = 0;
for (int i = 1; i <= 50; i++)
{
if (color[i])//该颜色存在
if (hungarian(i) > k)//注意匈牙利这里的参数赋值是i,不是color[i]
p[tol++] = i;//注意是赋值i,不是赋值color[i]
}
if (tol == 0)
printf("-1\n");
else
{
sort(p, p + tol);
for (int i = 0; i < tol; i++)
(i == 0) ? printf("%d", p[i]) : printf(" %d", p[i]);
printf("\n");
}
}
return 0;
}