50 years, 50 colors
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1789 Accepted Submission(s): 978
Problem Description
On Octorber 21st, HDU 50-year-celebration, 50-color balloons floating around the campus, it‘s so nice, isn‘t it? To celebrate this meaningful day, the ACM team of HDU hold some fuuny games. Especially, there will be a game named "crashing color balloons".
There will be a n*n matrix board on the ground, and each grid will have a color balloon in it.And the color of the ballon will be in the range of [1, 50].After the referee shouts "go!",you can begin to crash the balloons.Every time you can only choose one kind
of balloon to crash, we define that the two balloons with the same color belong to the same kind.What‘s more, each time you can only choose a single row or column of balloon, and crash the balloons that with the color you had chosen. Of course, a lot of students
are waiting to play this game, so we just give every student k times to crash the balloons.
Here comes the problem: which kind of balloon is impossible to be all crashed by a student in k times.
Input
There will be multiple input cases.Each test case begins with two integers n, k. n is the number of rows and columns of the balloons (1 <= n <= 100), and k is the times that ginving to each student(0 < k <= n).Follow a matrix A of n*n, where Aij denote the
color of the ballon in the i row, j column.Input ends with n = k = 0.
Output
For each test case, print in ascending order all the colors of which are impossible to be crashed by a student in k times. If there is no choice, print "-1".
Sample Input
1 1 1 2 1 1 1 1 2 2 1 1 2 2 2 5 4 1 2 3 4 5 2 3 4 5 1 3 4 5 1 2 4 5 1 2 3 5 1 2 3 4 3 3 50 50 50 50 50 50 50 50 50 0 0
Sample Output
-1 1 2 1 2 3 4 5 -1
题意:n*n的地图上有 1-50 种颜色的气球。 问哪几种颜色的气球不能在k步之内全部消灭掉。 每一步可以消灭一排或着一列 这种颜色的气球。
做法:简单的二分匹配,每种颜色都进行一次二分匹配,最大匹配就是最小顶点覆盖,也就是需要消灭所有这种颜色的 最小步数。 和k比下大小就可以了。
#include<stdio.h> #include<string.h> #define N 150 int visit[N]; int mark[N]; int match[N][N]; int n,m,k; int dfs(int x) { int i; for(i=1;i<=m;i++)//对左边的节点x与右边的节点进行逐一检查 { if(!visit[i]&&match[x][i]) { visit[i]=1;//标记检查过的点 if(mark[i]==-1||dfs(mark[i])) //mark如果没男的,就直接给个老公,如果已经有老公,搜他老公有没有喜欢的,有的话,该女配新男;;; {//|| 前面过了 后面不运行;; mark[i]=x;//修改匹配关系 return 1; } } } return 0; } int hungary () { memset(mark,-1,sizeof(mark)); int max=0,j; for(j=1;j<=n;j++)//对做部分顶点逐个进行遍历 { memset(visit,0,sizeof(visit)); if(dfs(j)) max++; } return max; } int mp[150][150]; int main() { int i,max; while(scanf ("%d%d",&n,&k),n||k) //k 个配 { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%d",&mp[i][j]); } } m=n; int fir=1; for(int col=1;col<=50;col++) { memset(match,0,sizeof(match)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(mp[i][j]==col) { match[i][j]=1; } } } max=hungary(); if(max>k) { if(fir) { fir=0; printf("%d",col); } else printf(" %d",col); } } if(fir) puts("-1"); else puts(""); } return 0; } /*http://blog.csdn.net/leolin_/article/details/7199688 在二分图中: 程序中涉及的变量说明:n为二分图的左部分顶点个数(顶点标号1到n)、 m为二分图的右部分顶点个数(顶点标号为1-m), k为左右顶点的配对关系个数(保存在match二维数组中); 最小边覆盖 = 最大独立集 = 顶点个数n -最小顶点覆盖( 最大匹配) 【无向图的最大独立数】: 从V个顶点中选出k个顶,使得这k个顶互不相邻。 那么最大的k就是这个图的最大独立数。 【无向图的最大团】: 从V个顶点选出k个顶,使得这k个顶构成一个完全图,即该子图任意两个顶都有直接的边。 【最小路径覆盖(原图不一定是二分图,但必须是有向图,拆点构造二分图)】:在图中找一些路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联。最小路径覆盖 = |V| - 最大匹配数 【最小边覆盖(原图是二分图)】:在图中找一些边,使之覆盖了图中所有顶点,且任何一个顶点有且只有一条边与之关联。最小边覆盖 = 最大独立集 = |V| - 最大匹配数 【最小顶点覆盖】:用最少的点(左右两边集合的点)让每条边都至少和其中一个点关联。 最大团 = 补图的最大独立集 最小边覆盖 = 二分图最大独立集 = |V| - 最小路径覆盖 //二分图 最小路径覆盖 = |V| - 最大匹配数 //有向图 最小顶点覆盖 = 最大匹配数 最小顶点覆盖 + 最大独立数 = |V| 最小割 = 最小点权覆盖集 = 点权和 - 最大点权独立集 */ /* (1)最小点路径覆盖: 有向图中,用最少的没有交集(一个点只走一遍)的边覆盖所有的点. 建立一个新图,将G中的每个点i在新图中拆成两个点i'、i'',若G中存在边<i, j>则在新图中连边<i', j''>,显然新图是一个二分图,求其最大匹配,则(N-新图最大匹配的值)就是最小点路径覆盖值。 时间复杂度:O(NM)(Hungary算法) */