题目连接
题意:
n * n 的图中, 放s种颜色的气球,然后给你k 次机会扎破这些气球
每次你扎破的这个气球时,可以扎破这一行或者这一列给这个气球颜色相同的气球
求k次机会内,有多少颜色的气球不能全部被扎破
思路:
倒推法:
我们需要求 求k次机会内,有多少颜色的气球不能全部被扎破
1)我们需要求 k次机会最多能扎破不同颜色的气球
2)也就是求出每个颜色的气球最少需要扎多少次
问题就转化为:求每个气球最少扎多少次就能破完
3)然后我思考每个颜色的气球是和它这一行或者这一列的颜色相同的气球
是绑定的,只要它一破他这一行或者一列就破完了
4)那怎么才能找到最少的呢? 扎破最少气球,把这个颜色的气球扎破,并且 这个颜色的气球会 带破(它所在的这一行或者一列)都破
5)是不是有点像图 把行 列看成2个集合。 进行连线,然后求最少的点把所有边(边:就是有气球) 覆盖
6)求一下 最小点覆盖 = 最大匹配
7)那是不是求一下最大匹配即可
AC代码:
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 105;
int N, K;
int G[maxn][maxn];
int Color[52];
bool Used[maxn];
int Link[maxn];
int nowColor;
vector<int> Ncolor;
void init(){
memset(G, 0, sizeof(G));
memset(Color, 0, sizeof(Color));
Ncolor.clear();
}
bool Dfs(int x){
for (int i = 1; i <= N; ++i) {
if (G[x][i] == nowColor && Used[i] == 0) {
Used[i] = 1;
if (Link[i] == -1 || Dfs(Link[i])){
Link[i] = x;
return true;
}
}
}
return false;
}
int Solve(int Color){
nowColor = Color;
memset(Link, -1, sizeof(Link));
int Ans = 0;
for(int i = 1; i <= N; ++i){
memset(Used, 0, sizeof(Used));
if (Dfs(i))
Ans++;
}
return Ans;
}
int main(){
while(~scanf("%d%d", &N, &K) && N && K){
init();
for (int i = 1; i <= N; ++i){
for (int j = 1; j <= N; ++j) {
scanf("%d", &G[i][j]);
Color[G[i][j]] = 1;
}
}
for(int i = 1; i <= 50; ++i){
if (Color[i] == 1) {
if(Solve(i) > K){
Ncolor.push_back(i);
}
}
}
if (Ncolor.size() == 0) {
printf("-1");
} else {
for(int i = 0; i < Ncolor.size(); ++i){
if(i) printf(" ");
printf("%d", Ncolor[i]);
}
}
printf("\n");
}
return 0;
}