hdu1498最小点覆盖

1.题意:(很是重要,理解了题意才能有转换为最小点覆盖的思路),对于一个n*n的矩阵,里面有一些颜色不同的气球(用1~50标记种类),给你K次机会,每次机会可以把某一行或者某一列中的某一种颜色全部消灭,问你K次消灭之后,有哪些颜色是你不能消灭完的....拿题目的案例 2 来画图:

我们这里只有K=1次机会去消除,,我们只有四种方式,从图中来看,1次机会我们不可能把1号颜色全部消除,但是有能把2号颜色消除的情况

2.分析:那么对于题目,我们的解决方案就是要把图中所有的颜色枚举一次,比如枚举 i 号颜色,那么就先求出全部消除 i 号颜色要用到的最小次数,那么对于求解这次最小次数...我们就考虑用到二分匹配匈牙利算法,并且是一个“最小点覆盖”的思路

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define MAX 101

int n,k;
int map[MAX][MAX];//存放整个图 map[i][j]的值 就是该方格的颜色
int link[MAX];
bool color[MAX],vis[MAX];//color[i] 为真 表示i号颜色在整个map中出现

bool dfs(int i,int co)//本次dfs过程中 是用 第i行 颜色为 co 去匹配,
{
	for(int j = 0; j < n; j ++)
	{
		if(!vis[j] && map[i][j] == co)
		{
			vis[j] = true;
			if(link[j] == -1 || dfs(link[j],co))
			{
				link[j] = i;return true;
			}
		}
	}
	return false;
}

int KM(int co)
{
	memset(link,-1,sizeof(link));
	int ans=0;
	for(int i = 0; i < n ; i ++)
	{
		memset(vis,false,sizeof(vis));
		if(dfs(i,co)) ans++;
	}
	return ans;
}

int main()
{
	int i,j;
	int ans[51],tol;//ans[] 存放的是要输出的不能消灭的颜色号,tol表示不能消灭的颜色数量
	while(scanf("%d%d",&n,&k),n+k)
	{
		memset(color,false,sizeof(color));
		memset(map,0,sizeof(map));
		for(i = 0; i < n; i ++)
		{
			for(j = 0; j < n; j ++)
			{
				scanf("%d",&map[i][j]);
				color[map[i][j]] = true;
			}
		}
		tol=0;
		for(i = 1; i <= 50; i ++)
		{
			if(color[i])//注意这里表示 i 号颜色是不是有的
			{
				if(KM(i) > k)//如果匹配最小消除i号颜色用到的次数大于k 意思就是不能消灭
					ans[tol++]=i;
			}
		}
		sort(ans,ans+tol);//注意排序
		if(tol == 0)
			printf("-1");
		else
			for(i = 0; i < tol; i ++)
				i == 0 ? printf("%d",ans[i]):printf(" %d",ans[i]);//这里是简单的格式控制,两数据中有空格
		printf("\n");
	}
	return 0;
}
时间: 2024-10-05 16:11:49

hdu1498最小点覆盖的相关文章

hdu1498 50 years, 50 colors --- 最小点覆盖

给一个矩阵,里面有一些不同颜色的气球.每次能够消灭一行或一列中某一种颜色的气球,问你在k次及以内,有哪些颜色的气球是不管怎样也消不完的. 那么思路就是,对每一种颜色的气球求最小点覆盖.>k 则为答案. 相当于 poj3041的加强版,由于矩阵中不是每个点都是等价的. #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm>

UVA-11419 SAM I AM (最小点覆盖)

题目大意:在一个n*m的网格中,有k个目标,现在可以任选一行或列消除在其上的所有目标,求出最少选择次数及选法. 题目分析:经典的最小点覆盖问题,并且输出一个最小点覆盖集.在求出最大匹配之后,以未覆盖的x点进行标记,沿着未覆盖->覆盖->未覆盖->覆盖...的路径标记,最后x中未标记的和y中标记的点构成最小点覆盖集. 代码如下: # include<iostream> # include<cstdio> # include<cstring> # incl

hdu 1054 Strategic Game 二分图最小点覆盖

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1054 题意: 给出一个无向图,求最小点覆盖. 思路: 用网络流来做设立一个超级源点和一个超级汇点. 每个点拆成i和i'. 从超级源点向点i连一条边,容量为1. 从i’向超级汇点连一条边,容量为1. 从i向i'连一条边,容量为正无穷. 然后求最小割/2.因为拆点拆成了2个. 也可以用二分图匹配来做,也是求出最大匹配然后/2. 1 #include <bits/stdc++.h> 2 using na

POJ2226 Muddy Fields(二分图最小点覆盖集)

题目给张R×C的地图,地图上*表示泥地..表示草地,问最少要几块宽1长任意木板才能盖住所有泥地,木板可以重合但不能盖住草地. 把所有行和列连续的泥地(可以放一块木板铺满的)看作点且行和列连续泥地分别作为XY部,每一块泥地看作边.这样就构造出了一个二分图. 那么,问题就是在这个二分图中就是选出最少的点覆盖所有的边,即二分图最小点覆盖集,而二分图最小点覆盖集=二分图最大匹配. 1 #include<cstdio> 2 #include<cstring> 3 #include<qu

UVa11419 SAM I AM(构造最小点覆盖)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27475 [思路] 二分图的最小点覆盖以及构造最小覆盖. 可见:http://www.tuicool.com/articles/jmAnEb [代码] #include<cstdio> #include<cstring> #include<vector> #include<iostream> using namespace st

POJ3041Asteroids(最小点覆盖+然而并不是很理解why)

Asteroids Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 18289   Accepted: 9968 Description Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K as

二分图匹配 + 最小点覆盖 - Vertex Cover

Vertex Cover Problem's Link Mean: 给你一个无向图,让你给图中的结点染色,使得:每条边的两个顶点至少有一个顶点被染色.求最少的染色顶点数. analyse: 裸的最小点覆盖问题,二分图的最大匹配,直接套模版即可. Time complexity: O(N^2) view code

hdu 1151 或 poj 1422 二分图 最小点覆盖集

最小点覆盖集的裸题,只要“拆点建边”然后求出最大匹配,则:最小点覆盖集的大小 = 点数 - 最大匹配 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 121; 7 const int M = 5000; 8 bool visit[N]; 9 int mark[N]; 10 int head[N]; 11 int

POJ3041 Asteroids【二分图最小点覆盖】

题目链接: http://poj.org/problem?id=3041 题目大意: 有一个N*N的矩阵,有些格子上有障碍物(坐标为(x,y) ),在消除这些障碍物的时候,可以一次性消除 该障碍物同一行所有的障碍物,或是一次性消除该障碍物同一列所有的障碍物.只能选择清理该行或是 清理该列.问:最小进行多少次消除,就可以清理所有的障碍物. 思路: 可以将每一行当做一个点,这样总共有N个点,作为二分图的一边.将每一列当做一个点,这样又有N 个点,作为二分图的另一边.将有障碍物的行点和列点连接起来,每