1 /*HDU1498 2 题目大意: 3 给出N*N(100以内)的矩阵,矩阵上填气球的标号(1--50),给定 K 4 问,哪些编号的气球是不能一次在K次以内拿完的。每次拿取的过程是:选择一行或者一列,再在其中选一个气球,其余的下一次不能再选。 5 6 思考: 7 变种的棋盘问题。 8 但是要枚举气球编号(分类讨论). 9 这样,就是找到最大的匹配,即最多能放置互不在同一行或一列的气球。 10 这个匹配数小于等于K,则气球能全部被拿完。 11 复杂度为:O(50*200*200) 12 */ 13 #include <iostream> 14 #include <cmath> 15 #include <algorithm> 16 #include <string.h> 17 #include <stdio.h> 18 #include <set> 19 #include <stack> 20 #include <vector> 21 #define maxn 210 22 using namespace std; 23 vector<int> G[maxn]; 24 int match[maxn]; 25 bool visit[maxn]; 26 int ans[55]; 27 int mat[maxn][maxn]; 28 int cnt; 29 int N,K; 30 void read(){ 31 for(int i=1;i<=N;i++){ 32 for(int j=1;j<=N;j++) scanf("%d",&mat[i][j]); 33 } 34 } 35 void init(int k){ 36 for(int i=1;i<=2*N;i++) G[i].clear(); 37 for(int i=1;i<=N;i++){ 38 for(int j=1;j<=N;j++){ 39 if (mat[i][j]==k){ 40 int a=i,b=j+N; 41 G[a].push_back(b); 42 G[b].push_back(a); 43 } 44 } 45 } 46 } 47 bool dfs(int s)//找到从s点出发的可增广路 48 { 49 for(int i=0;i<G[s].size();i++){ 50 int v=G[s][i]; 51 if (!visit[v]){ 52 visit[v]=true; 53 if (match[v]==0 || dfs(match[v])){//说明v对应的项有增广路 54 match[v]=s;//修改v的对应项(即互斥点)是s 55 return true; 56 } 57 } 58 } 59 return false; 60 } 61 62 int hungary(){ 63 int ans=0; 64 memset(match,0,sizeof(match));//清空匹配 65 for(int i=1;i<=2*N;i++){ 66 memset(visit,0,sizeof(visit));//注意清空增广路 67 if (dfs(i)) ans++; 68 } 69 return ans/2; 70 } 71 void solve(){ 72 cnt=0; 73 for(int i=1;i<=50;i++){ 74 init(i); 75 if (hungary()>K) ans[cnt++]=i; 76 } 77 } 78 int main(){ 79 while(cin>>N>>K){ 80 if (!N && !K) break; 81 read(); 82 solve(); 83 if (cnt==0) puts("-1"); 84 else { 85 for(int i=0;i<cnt;i++) 86 if (i==cnt-1) printf("%d ",ans[i]);else printf("%d ",ans[i]); 87 } 88 } 89 }