首页 > 其他分享 >C1002 泥泞的牧场题解

C1002 泥泞的牧场题解

时间:2023-02-21 20:13:25浏览次数:47  
标签:int 题解 top dfs else while 泥泞 && C1002

题目描述

大雨侵袭了牧场。牧场是一个 \(R \times C\) 的矩形,其中 \(1\leq R,C\leq 50\)。大雨将没有长草的土地弄得泥泞不堪,可是小心的奶牛们不想在吃草的时候弄脏她们的蹄子。 为了防止她们的蹄子被弄脏,农场主决定在泥泞的牧场里放置一些木板。每一块木板的宽度为 \(1\) 个单位,长度任意。每一个板必须放置在平行于牧场的泥地里。农场主想使用最少的木板覆盖所有的泥地。一个木板可以重叠在另一个木板上,但是不能放在草地上。

输入格式

第一行:两个整数 \(R\) 和 \(C\)。

第二行到第 \(R + 1\) 行:第 \(i + 1\) 行有 \(C\) 个字符串,表示第 \(R\) 的地形,“*”
代表泥地,“.”代表草地。

输出格式

一个整数:表示最少需要多少木板。


40pts

暴力dfs,枚举每个泥泞,看是往上、下、左、右哪个方向延伸。最坏复杂度 \(nm\times 4^{nm}\),基本无法得分。但我们可以在此基础上进行最优性剪枝(在当前答案大于全局答案时返回)、跳过草地、特判单个泥泞、特判狭窄泥泞、特判左向 \(left-right-single\) 、右向 \(up-down-single\)和使用栈等一系列的优化来获得 \(60\) 分的好成绩。
代码:

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define INF 0x7fffffff
#define MAXN 100005
#define eps 1e-9
#define foru(a,b,c)	for(int a=b;a<=c;a++)
#define RT return 0;
#define db(x)	cout<<endl<<x<<endl;
#define LL long long
#define LXF int
#define RIN rin()
#define HH printf("\n")
using namespace std;
inline LXF rin(){
	LXF x=0,w=1;
	char ch=0;
	while(ch<'0'||ch>'9'){ 
	if(ch=='-') w=-1;
	ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
	x=x*10+(ch-'0');
	ch=getchar();
	}
	return x*w;
}
int n,m;
int a[70][70];
int ans=INF;
void draw(){
	foru(i,1,n){
		foru(j,1,m){
			cout<<a[i][j]<<' ';
		}
		HH;
	}
}
class Node{
	public:
		int x,y;
};
void dfs(int x,int y,int as){
	if(as>=ans)		return ;
	if(x==n+1){//end
		ans=min(ans,as);
		return ;
	}
	
	
	if(a[x][y]!=1){//continue
		if(y==m)	dfs(x+1,1,as);
		else	dfs(x,y+1,as);
		return ;
	}
	if(a[x-1][y]==0 && a[x+1][y]==0 && a[x][y+1]==0 && a[x][y-1]==0){//single_check
		a[x][y]=2;
		if(y==m)	dfs(x+1,1,as+1);
		else	dfs(x,y+1,as+1);
		a[x][y]=1;
		return ;
	}
	stack<Node> s;//recover
	
	if(a[x-1][y]==0 && a[x+1][y]==0){//up-down-single
		for(int i=y;;i--){
			if(a[x][i]==0){
				break;
			}
			if(a[x][i]==1)	s.push((Node){x,i});
			a[x][i]=2;
		}
		if(y==m)	dfs(x+1,1,as+1);
		else	dfs(x,y+1,as+1);
		
		while(!s.empty()){
			a[s.top().x][s.top().y]=1;
			s.pop();
		}
		for(int i=y;;i++){
			if(a[x][i]==0){
				break;
			}
			if(a[x][i]==1)	s.push((Node){x,i});
			a[x][i]=2;
		}
		if(y==m)	dfs(x+1,1,as+1);
		else	dfs(x,y+1,as+1);
		
		while(!s.empty()){
			a[s.top().x][s.top().y]=1;
			s.pop();
		}
		return ;
	}
	
	if(a[x][y-1]==0 && a[x][y+1]==0){//left-right-single
		for(int i=x;;i--){
			if(a[i][y]==0){
				break;
			}
			if(a[i][y]==1)	s.push((Node){i,y});
			a[i][y]=2;
		}
		if(y==m)	dfs(x+1,1,as+1);
		else	dfs(x,y+1,as+1);
		
		while(!s.empty()){
			a[s.top().x][s.top().y]=1;
			s.pop();
		}
		for(int i=x;;i++){
			if(a[i][y]==0){
				break;
			}
			if(a[i][y]==1)	s.push((Node){i,y});
			a[i][y]=2;
		}
		if(y==m)	dfs(x+1,1,as+1);
		else	dfs(x,y+1,as+1);
		
		while(!s.empty()){
			a[s.top().x][s.top().y]=1;
			s.pop();
		}
		return ;
	}
	
	
	//last,all
	//do x
	for(int i=x;;i--){
		if(a[i][y]==0){
			break;
		}
		if(a[i][y]==1)	s.push((Node){i,y});
		a[i][y]=2;
	}
	if(y==m)	dfs(x+1,1,as+1);
	else	dfs(x,y+1,as+1);
	
	while(!s.empty()){
		a[s.top().x][s.top().y]=1;
		s.pop();
	}
	for(int i=x;;i++){
		if(a[i][y]==0){
			break;
		}
		if(a[i][y]==1)	s.push((Node){i,y});
		a[i][y]=2;
	}
	if(y==m)	dfs(x+1,1,as+1);
	else	dfs(x,y+1,as+1);
	
	while(!s.empty()){
		a[s.top().x][s.top().y]=1;
		s.pop();
	}
	
	
	
	//do y
	for(int i=y;;i--){
		if(a[x][i]==0){
			break;
		}
		if(a[x][i]==1)	s.push((Node){x,i});
		a[x][i]=2;
	}
	if(y==m)	dfs(x+1,1,as+1);
	else	dfs(x,y+1,as+1);
	
	while(!s.empty()){
		a[s.top().x][s.top().y]=1;
		s.pop();
	}
	for(int i=y;;i++){
		if(a[x][i]==0){
			break;
		}
		if(a[x][i]==1)	s.push((Node){x,i});
		a[x][i]=2;
	}
	if(y==m)	dfs(x+1,1,as+1);
	else	dfs(x,y+1,as+1);
	
	while(!s.empty()){
		a[s.top().x][s.top().y]=1;
		s.pop();
	}
}
signed main(){
	// freopen("cover.in","r",stdin);
	// freopen("cover.out","w",stdout);
	n=RIN,m=RIN;
	for(int i=1;i<=n;i++){
		string s;
		cin>>s;
		for(int j=0;j<m;j++){
			if(s[j]=='*'){
				a[i][j+1]=1;
			}
		}
	}
	dfs(1,1,0);
	cout<<ans;
	return 0;
}

100pts

考虑按照套路进行建模。

我们把所有的泥地分成若干个横连通块和纵连通块,把他们分别作为二分图的左右两部分。泥泞意味着把泥泞所在的横连通块和纵联通块连边。于是我们要找到最少的木板,变成了一个最小点覆盖问题。所以直接求二分图最大匹配即可。

为什么是最小点覆盖呢?因为我们每找到一个点,就相当于选中了一个“横/纵联通块”,放置了一块木板,而在二分图里的“被控制”的边,对应到题目就代表着“这个联通块上的泥泞已经被木板覆盖”,所以可以用最小点覆盖解决。

代码:

#include <bits/stdc++.h>
#include <bits/extc++.h>
#define INF 0x7fffffff
#define MAXN 100005
#define eps 1e-9
#define foru(a,b,c)	for(int a=b;a<=c;a++)
#define RT return 0;
#define db(x)	cout<<endl<<x<<endl;
#define LL long long
#define LXF int
#define RIN rin()
#define HH printf("\n")
using namespace std;
inline LXF rin(){
	LXF x=0,w=1;
	char ch=0;
	while(ch<'0'||ch>'9'){ 
	if(ch=='-') w=-1;
	ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
	x=x*10+(ch-'0');
	ch=getchar();
	}
	return x*w;
}
int n,m,xx,yy;
int a[70][70],b[70][70];
bool c[70][70];
int ans=0;
const int MAXM=500005;
class Edge{
	public:
		int v,w,nxt;
}e[MAXM<<1];
int ehead[MAXN],ecnt;
inline void add_e(int u,int v,int w=0){e[++ecnt]={v,w,ehead[u]},ehead[u]=ecnt;}
bool vis[MAXN];
int match[MAXN];
bool find(int x){
	for(int i=ehead[x];i;i=e[i].nxt){
		int v=e[i].v;
		if(vis[v])	continue;
		vis[v]=1;
		if(match[v]==0 || find(match[v])){
			match[v]=x;
			return true;
		}
	}
	return false;
}
signed main(){
	n=RIN,m=RIN;
	for(int i=1;i<=n;i++){
		string s;
		cin>>s;
		for(int j=1;j<=m;j++){
			if(s[j-1]=='*'){
				c[i][j]=true;
				if(j>1&&c[i][j-1]){
					a[i][j]=a[i][j-1];
				}else{
					a[i][j]=++xx;
				}
				if(i>1&&c[i-1][j]){
					b[i][j]=b[i-1][j];
				}else{
					b[i][j]=++yy;
				}
			}
		}
	}
	foru(i,1,n){
		foru(j,1,m){
			if(c[i][j]){
				add_e(a[i][j],b[i][j]+xx+1);
				add_e(b[i][j]+xx+1,a[i][j]);
			}
		}
	}
	foru(i,1,xx){
		memset(vis,0,sizeof vis);
		if(find(i)){
			ans++;
		}
	}
	cout<<ans;
	return 0;
}

标签:int,题解,top,dfs,else,while,泥泞,&&,C1002
From: https://www.cnblogs.com/Cap1taL/p/17142231.html

相关文章

  • vue开发大屏项目屏幕适配问题解决方案
    1.新建自定义指令文件如下: 2.文件中插入一下代码:import{App,Directive,DirectiveBinding,nextTick}from'vue'import{throttle}from'lodash-es'import......
  • C1001 游戏题解
    题目描述\(everlasting\)觉得太无聊了,于是决定和蒟蒻\(yyc\)玩游戏!他们会玩\(T\)轮游戏,每轮游戏中有若干局,他们的初始积分为\(1\),每局的分值为\(k\),输的人的得分......
  • Vue前端框架Element 的form表单项el-form-item的label中空格不起效和多个空格只显示一
    搜索了一下,大部分是说使用slot解决,但是使用&nbsp;&nbsp;只显示一个后又看到一篇文章Vue使用&nbsp空白占位符-钟小嘿-博客园(cnblogs.com)使用转义,但要用v-html,......
  • 第九届蓝桥杯题解
    第九届蓝桥杯题解A,第几天packagetrain;publicclasstest_27{publicstaticvoidmain(String[]args){System.out.println(31+29+31+30+4);}}......
  • P9064 [yLOI2023] 苦竹林 题解
    题目传送门题目大意给定一个长度为\(n\)序列\(a\),从中选取\(m\)个,满足对任意的\(1\leqi,j\leqm\),都有\(|b_i-b_j|\leq\varepsilon\),其中,\(b\)是选出来......
  • 「题解」洛谷 P5829 【模板】失配树
    crashednb/se不过它解释为什么跳\(k\bmodd+d\)确实有点迷,不懂为什么直接跳\(k\bmodd\)会挂可以手摸一下峰峰峰的hack,从25开始跳。简单做法就是建出失配树然后......
  • 问题解决系列:证书续签的时候,nginx重启报错
    一、问题场景进行​​let'sencrypt​​​证书续签之后,​​nginx​​重启报错,提示如下:[MonFeb2010:23:40CST2023]Runreloadcmd:/bin/systemctlrestartnginxJobf......
  • abc290F 题解
    吸收恒等式、范德蒙德卷积。为什么我能切黄题的场我都没打啊/ll先考虑确定度数数组时怎么做。显然\(\sumx_i=2n-2\)。手玩一下发现答案是\(\sum[x_i>1]+1\)......
  • 【题解】P5644 [PKUWC2018]猎人杀
    供题人是树剖姐姐喵/se思路生成函数+子集反演+分治NTT.首先发现当前打中的猎人倒下之后,后面的猎人被射中的概率会随之变化,也就是说操作是有后效性的,不好处理。有......
  • LuoguP5354 [Ynoi2017]由乃的OJ题解
    P5354[Ynoi2017]由乃的OJPreface自己的由乃题一血,写篇题解纪念一下。Description给定一颗\(n\)个结点的树,每个结点都有一个权值\(a_i\)和一个位运算符\(\mathrm{......