题意:给出n*n的气球,有不同的颜色(最多有50种),每一次都可以选择把某一行或者某一列的某一种颜色的气球给弄破,问k次以后,有那几种颜色的气球是可以留下来的?
这道题目的关键是想到,把每一种颜色的气球单独拿出来考虑。比如先考录颜色编号为1的气球,把所有这种颜色的气球的横坐标列坐标相连,然后求最小顶点覆盖数,就是最少需要几次可以将这种颜色的气球全部弄破。如果大于k次,那么这种颜色的气球是可以留下来的。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 105
using namespace std;
int g[N][N], link[N], used[N], a[N][N], b[N];
int n, k , maxa, cnt, res;
int dfs(int u)
{
for (int v = 1; v <= n; v++)
if (g[u][v] && !used[v])
{
used[v] = 1;
if (link[v] == -1 || dfs(link[v]))
{
link[v] = u;
return 1;
}
}
return 0;
}
void color(int c)
{
memset(g, 0, sizeof(g));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (a[i][j] == c) g[i][j] = 1;
memset(link, -1, sizeof(link));
res = 0;
for (int i = 1; i <= n; i++)
{
memset(used, 0, sizeof(used));
if (dfs(i)) res++;
}
if (res > k)
{
cnt++;
b[cnt] = c;
}
}
int main()
{
while (~scanf("%d%d", &n, &k) && !(n == 0 && k == 0))
{
cnt = 0;
maxa = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
scanf("%d", &a[i][j]);
if (a[i][j] > maxa) maxa = a[i][j];
}
for (int i = 1; i <= maxa; i++)
color(i);
if (cnt != 0)
{
for (int i = 1; i < cnt; i++)
printf("%d ", b[i]);
printf("%d\n", b[cnt]);
}
else printf("-1\n");
}
return 0;
}