依次计算每种颜色的最小点覆盖数,如果最小点覆盖数大于 k,则该颜色气球不能全部扎破。
将气球图看作二分图,行看作一边,列看作一边,如果 mp[i][j] 等于该颜色,则表示 i 和 j 之间存在一条边。
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 105;
const int MAXC = 55;
int mp[MAXN][MAXN]; //气球图
int match[MAXN];
int vis[MAXN];
int color[MAXC]; //是否存在该颜色的气球
int ans[MAXC];
int n, k;
//查找从结点x出发的增广路径
bool find(int x, int c)
{
for (int i = 0; i < n; i++)
{
if (!vis[i] && mp[x][i] == c)
{
vis[i] = 1;
if (match[i] == -1 || find(match[i], c))
{
match[i] = x;
return 1;
}
}
}
return 0;
}
//计算颜色c的最小点覆盖数(即最大匹配数)
int maxMatch(int c)
{
memset(match, -1, sizeof(match));
int num = 0;
for (int i = 0; i < n; i++)
{
memset(vis, 0, sizeof(vis));
if (find(i, c))
++num;
}
return num;
}
int main()
{
while (cin >> n >> k)
{
if (n == 0 && k == 0)
break;
for (int i = 0; i < n; i++) //输入气球图
{
for (int j = 0; j < n; j++)
{
cin >> mp[i][j];
color[mp[i][j]] = 1;
}
}
int total = 0;
for (int i = 0; i < MAXC; i++)
{
if (color[i] == 0)
continue;
if (maxMatch(i) > k)
ans[total++] = i;
}
if (total == 0)
cout << -1 << endl;
else
{
for (int i = 0; i < total - 1; i++)
cout << ans[i] << " ";
cout << ans[total - 1] << endl;
}
}
return 0;
}
继续加油。