牛客练习赛30: D. 消消乐(二分匹配+输出最小点覆盖)

版权声明:本文为博主原创文章,你们可以随便转载 https://blog.csdn.net/Jaihk662/article/details/83662773

链接:https://ac.nowcoder.com/acm/contest/216/D
来源:牛客网
 

题目描述

r神在和小b比赛玩一个名为“消消乐”的游戏,在一个n*m的棋盘上,一些棋子分布在格点上,游戏玩家有一个名为超蓝光波的武器,可以消除一行或者一列的所有棋子,使用超蓝光波需要耗费一点能量,消除完所有的棋子之后,花费能量越少得分越高。

r神为了超过排名第一的小b,夺得荣誉称号“天下第一”,他需要寻求你的帮助,他希望知道最少需要使用多少次“超蓝光波”,以及在哪行、哪列使用。

输入描述:

第一行两个正整数n(n<=2000),m(m<=2000);

接下来n行,每行m个字符,表示棋盘,其中“.”表示该处没有棋子,“*”表示该处有棋子,棋子个数<=100000

输出描述:

第一行输出一个正整数,表示最少需要使用的“超蓝光波”次数

第二行N+1个正整数,第一个数为N,表示需要消掉的行数,从小到大输出每个需要消除的行号

第三行M+1个正整数,第一个数为M,表示需要消掉的列数,从小到大输出每个需要删除的列号

如果有多种情况,任意输出一种即可。

输入

3 4
.*..
**.*
.*..

输出

2
1 2
1 2

很容易发现这题就是个二分匹配

如果(x, y)上有棋子,那么第x行向第y列连一条边

求出最小点覆盖就是答案

然而这题还需要输出一种最小点覆盖方案

二分匹配时一些变量如下

  • visx[p]/visy[p]:左边/右边第p个点是否被标记
  • L[p]/R[p]:最大匹配下,左边/右边第p个点连接了对面的哪个点(如果这个点没有与任何点相连,为-1)

步骤如下:

  1. 先进行一次二分匹配
  2. 清空visx[]和visy[],并对左边所有没有匹配成功的点,再次尝试匹配
  3. 这个时候所有visx[]为0,visy[]不为0的点即最小点覆盖中的点
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
char str[2005];
int k, n, m, visx[2005], visy[2005], L[2005], R[2005];
vector<int> G[2005], F;
int Sech(int x)
{
	int i, v;
	visx[x] = 1;
	for(i=0;i<G[x].size();i++)
	{
		v = G[x][i];
		if(visy[v]==0)
		{
			visy[v] = 1;
			if(R[v]==-1 || Sech(R[v]))
			{
				R[v] = x, L[x] = v;
				return 1;
			}
		}
	}
	return 0;
}
int main(void)
{
	int i, j, ans;
	scanf("%d%d", &n, &m);
	for(i=1;i<=n;i++)
	{
		scanf("%s", str+1);
		for(j=1;j<=m;j++)
		{
			if(str[j]=='*')
				G[i].push_back(j);
		}
	}
	ans = 0;
	memset(L, -1, sizeof(L));
	memset(R, -1, sizeof(R));
	for(i=1;i<=n;i++)
	{
		memset(visy, 0, sizeof(visy));
		if(Sech(i))
			ans++;
	}
	memset(visx, 0, sizeof(visx));
	memset(visy, 0, sizeof(visy));
	printf("%d\n", ans);
	for(i=1;i<=n;i++)
	{
		if(L[i]==-1)
			Sech(i);
	}
	for(i=1;i<=n;i++)
	{
		if(visx[i]==0)
			F.push_back(i);
	}
	printf("%d", F.size());
	for(i=0;i<F.size();i++)
		printf(" %d", F[i]);
	puts("");
	F.clear();
	for(i=1;i<=m;i++)
	{
		if(visy[i])
			F.push_back(i);
	}
	printf("%d", F.size());
	for(i=0;i<F.size();i++)
		printf(" %d", F[i]);
	puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/83662773