http://acm.hdu.edu.cn/showproblem.php?pid=1498
题意:给出一个 n*n 的矩阵,里面的数字代表一种颜色,每次能炸掉一排或者一列的相同颜色的气球,问有哪些颜色的气球不能在 k 次内炸完的,从小到大输出,能炸完输出-1.
思路:先存下点,用一个数字标记颜色是否出现过,然后遍历每一种颜色,再把这种颜色的行号和列号连边,跑一遍匈牙利,如果得到的结果大于 k 那么这种颜色就不行。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <iostream>
#include <stack>
#include <map>
#include <queue>
using namespace std;
#define N 100010
#define INF 0x3f3f3f3f
struct node
{
int nxt, v;
}edge[*];
int mp[][];
int head[], tot;
bool vis[], col[];
int ans[];
int match[], n, k; void add(int u, int v)
{
edge[tot].v = v; edge[tot].nxt = head[u]; head[u] = tot++;
} bool dfs(int u)
{
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(!vis[v]) {
vis[v] = ;
if(match[v] == - || dfs(match[v])) {
match[v] = u;
return true;
}
}
}
return false;
} int main()
{
while(scanf("%d%d", &n, &k), n + k) {
memset(mp, , sizeof(mp));
memset(col, , sizeof(col));
for(int i = ; i <= n; i++) {
for(int j = ; j <= n; j++) {
scanf("%d", &mp[i][j]);
col[mp[i][j]] = ;
}
}
int l = ;
for(int i = ; i <= ; i++) {
if(col[i]) {
tot = ;
memset(head, -, sizeof(head));
for(int j = ; j <= n; j++) {
for(int k = ; k <= n; k++) {
if(mp[j][k] == i) {
add(j, k);
}
}
}
memset(match, -, sizeof(match));
int tmp = ;
for(int j = ; j <= n; j++) {
memset(vis, , sizeof(vis));
if(dfs(j)) tmp++;
}
if(tmp > k) ans[l++] = i;
}
}
// printf("ans : ");
for(int i = ; i < l; i++) {
if(i != l - ) printf("%d ", ans[i]);
else printf("%d\n", ans[i]);
}
if(l == ) printf("-1\n");
}
return ;
}