CF 525D(Arthur and Walls-贪心2*2方格补全)

文章介绍了一种通过最小化墙壁拆除来优化公寓内部布局的方法,确保每个房间均为矩形。利用BFS算法遍历并识别需要修改的墙壁位置,最终输出修改后的公寓平面图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D. Arthur and Walls
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Finally it is a day when Arthur has enough money for buying an apartment. He found a great option close to the center of the city with a nice price.

Plan of the apartment found by Arthur looks like a rectangle n × m consisting of squares of size 1 × 1. Each of those squares contains either a wall (such square is denoted by a symbol "*" on the plan) or a free space (such square is denoted on the plan by a symbol ".").

Room in an apartment is a maximal connected area consisting of free squares. Squares are considered adjacent if they share a common side.

The old Arthur dream is to live in an apartment where all rooms are rectangles. He asks you to calculate minimum number of walls you need to remove in order to achieve this goal. After removing a wall from a square it becomes a free square. While removing the walls it is possible that some rooms unite into a single one.

Input

The first line of the input contains two integers n, m (1 ≤ n, m ≤ 2000) denoting the size of the Arthur apartments.

Following n lines each contain m symbols — the plan of the apartment.

If the cell is denoted by a symbol "*" then it contains a wall.

If the cell is denoted by a symbol "." then it this cell is free from walls and also this cell is contained in some of the rooms.

Output

Output n rows each consisting of m symbols that show how the Arthur apartment plan should look like after deleting the minimum number of walls in order to make each room (maximum connected area free from walls) be a rectangle.

If there are several possible answers, output any of them.

Sample test(s)
input
5 5
.*.*.
*****
.*.*.
*****
.*.*.
output
.*.*.
*****
.*.*.
*****
.*.*.
input
6 7
***.*.*
..*.*.*
*.*.*.*
*.*.*.*
..*...*
*******
output
***...*
..*...*
..*...*
..*...*
..*...*
*******
input
4 5
.....
.....
..***
..*..
output
.....
.....
.....
.....



贪心,如果一个‘*’必须挖掉,则必然存在1个2*2方格,只有它1个'*'

所以用bfs遍历待挖’*‘,注意边界


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<queue>
#include<vector>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (2000+10)
typedef long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int n,m;
char s[MAXN][MAXN];
int a[MAXN][MAXN]={0};
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; 
int dire[3]={-1,0,1}; 
bool inside(int i,int j){return (1<=i&&i<=n&&1<=j&&j<=m);}
queue<pair<int,int> > q;
int sum(int i,int j)
{
	return a[i][j]+a[i][j+1]+a[i+1][j]+a[i+1][j+1];
}
bool shall_destroy(int i,int j)
{
	if (a[i][j]) return 0;
	if (sum(i,j)==3||sum(i-1,j)==3||sum(i,j-1)==3||sum(i-1,j-1)==3) return 1;
	return 0;
}
int main()
{
//	freopen("Walls.in","r",stdin);
	
	scanf("%d%d",&n,&m);
	For(i,n)
	{
		scanf("%s",s[i]+1);
	}
	For(i,n)
		For(j,m) if (s[i][j]=='.') a[i][j]=1;
	
	while(!q.empty()) q.pop();
	
	
		
	For(i,n) 
		For(j,m)
			if (shall_destroy(i,j)) 
			{
				a[i][j]=1;
				q.push(make_pair(i,j));
			}
	
	while(!q.empty())
	{
		pair<int,int> now=q.front();
		q.pop();
		int x=now.first,y=now.second;
		Fork(i,x-1,x+1)
			Fork(j,y-1,y+1)
				if(inside(i,j)&&shall_destroy(i,j))
				{
					a[i][j]=1;
					q.push(make_pair(i,j));
				} 
		 
	}
	
	
	For(i,n)
	{
		For(j,m)
			if (a[i][j]) putchar('.');
			else putchar('*');
		printf("\n");
	}
	
	return 0;
}





<think>好的,我现在要帮助用户解决如何实现继承自Actor类的Hero类的Java示例代码。首先,我需要回顾一下用户提供的引用内容,特别是引用[1]和引用[2],因为它们提到了继承的相关知识。 根据引用[1],继承在Java中的实现需要注意几点:父类的私有方法和属性不能被继承,父类的构造方法也不能被继承,子类需要通过super调用父类构造方法。如果子类不显式调用super,默认会调用父类的无参构造。此外,引用[2]提到,Hero类继承自Actor类,必须重写Actor中的抽象方法,特别是setHealth方法。 首先,我需要确定Actor类的结构。假设Actor是一个抽象类,可能包含抽象方法,比如setHealth。Hero作为子类,必须实现这些抽象方法。另外,构造方法的处理也很重要。如果Actor有构造方法,Hero的构造方法需要通过super来调用父类的构造方法。 接下来,考虑代码的结构。Actor类可能有属性如health,以及抽象方法setHealth。Hero类继承Actor后,需要实现setHealth方法。同时,可能还需要添加Hero特有的属性和方法,比如name或者level,并重写toString方法以便测试。 然后,我需要确保Hero类的构造方法正确调用父类的构造方法。如果Actor有一个接受health参数的构造方法,那么Hero的构造方法应该使用super(health)来初始化父类的属性。同时,Hero自己的属性也需要在构造方法中初始化。 另外,引用[1]还提到,父类的私有属性在子类中不能被直接访问,所以如果health在Actor中是私有的,Hero需要通过父类提供的方法(比如getter或setter)来访问或修改它。但在引用[2]的例子中,setHealth方法是直接设置this.health,可能说明health在Actor中是protected或者包私有,允许子类直接访问。 还需要注意,如果Actor类有抽象方法,Hero必须全部实现。比如除了setHealth,可能还有其他抽象方法需要实现,但根据用户的问题,可能只需要关注setHealth。 最后,测试代码部分,创建Hero实例并调用方法,验证继承是否正确。例如,创建Hero对象,设置health,并打印信息。 现在把这些思路整理成代码。首先定义Actor抽象类,包含health属性和抽象方法setHealth。然后Hero类继承Actor,实现setHealth,并添加自己的属性。构造方法中使用super调用父类构造。可能还需要重写toString方法。 需要检查是否存在语法错误,比如是否正确使用extends,是否正确调用super,是否正确实现抽象方法等。确保代码符合Java语法规范,比如类名大写,方法正确覆盖等。 可能遇到的问题:如果Actor的构造方法没有无参构造,而子类没有显式调用super,会导致编译错误。因此,在Hero的构造方法中必须正确调用super。 综上所述,代码大致结构应该是: 1. 定义抽象类Actor,包含health属性和抽象方法setHealth。 2. Hero类继承Actor,实现setHealth方法。 3. Hero可能有自己的属性,如name,并在构造方法中初始化。 4. 使用super调用父类构造方法,传递必要的参数。 5. 测试代码创建Hero实例,调用方法验证功能。 现在根据这些步骤编写具体的代码示例,并确保符合用户提供的引用中的要求。</think>根据面向对象编程原则和Java继承特性,以下是实现Actor类和Hero子类的完整示例代码: ```java // 抽象基类Actor定义 abstract class Actor { protected int health; // 受保护属性可被子类直接访问 public Actor(int initialHealth) { this.health = initialHealth; } // 抽象方法必须被实现 public abstract void setHealth(int health); // 公共方法可被子类继承 public void displayStatus() { System.out.println("当前生命值: " + health); } } // Hero类继承实现 class Hero extends Actor { private String heroName; // 子类特有属性 private int level; // 子类特有属性 // 构造方法必须调用父类构造 public Hero(String name, int level, int initialHealth) { super(initialHealth); // 必须首先调用父类构造[^1] this.heroName = name; this.level = level; } // 实现父类抽象方法 @Override public void setHealth(int health) { // 通过父类受保护字段直接访问 if(health >= 0) { super.health = health; // 正确设置父类属性[^2] } } // 子类扩展方法 public void levelUp() { level++; System.out.println(heroName + "升级到 " + level + " 级!"); } // 重写父类方法 @Override public void displayStatus() { System.out.println("英雄名称: " + heroName); super.displayStatus(); System.out.println("等级: " + level); } } // 测试类 public class Main { public static void main(String[] args) { Hero arthur = new Hero("亚瑟", 1, 100); arthur.setHealth(150); arthur.levelUp(); arthur.displayStatus(); // 多态应用示例 Actor actor = new Hero("但丁", 5, 200); actor.setHealth(180); actor.displayStatus(); } } ``` 关键实现要点: 1. 构造方法链:通过`super(initialHealth)`显式调用父类构造方法,符合继承规范 2. 抽象方法实现:`@Override`注解确保正确覆盖父类抽象方法`setHealth()` 3. 访问控制:使用`protected`修饰符允许子类直接访问父类属性 4. 方法扩展:`levelUp()`方法展示子类特有功能 5. 方法重写:`displayStatus()`使用`@Override`增强父类方法功能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值