CodeForces 44J - Triminoes -搜索转构造

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20077

给你一个n*m的图,图上有‘.’代表挖走了的瓷砖,剩下的是 用w,b分别表示白色黑色的瓷砖

要求找出所有的 “ wbw ”这样的瓷砖,替换成 aaa/bbb/ccc/ddd 任意一个

问你能否把所有的w/b瓷砖按照上述规则替换成   aaa/bbb/ccc/ddd  并且要求,用连续三个字母替换之后的瓷砖不能和相同字母相邻

也就是  不能 aaaaaa 但是可以aaabbb


一开始想dfs ,找出所有 只连接着一个b 的w (此W 必然只能往b的方向填) .我们把这样只有一个方向发展的w成为 度数为1

先找出所有度数为1的w 填掉,再重新搜 不断 找度数为1的w,直到整个图找不到度数为1的w,此时检查 整个图是否填好了

如果没,则不存在方案, 其次 在填的过程中要注意判断 是否能 完整填上三个瓷砖。。。一直wa  on test 32


后来发现,从图的第一行第一列开始 按从左到右从上到下的顺序遍历每一个点,对于每一个W,如果他的左边是‘b’ ,则这个W一定往右填 (否则这个b无法被填上),如果他的左边不是‘b’,那么他只能往下填

按照这样的思路,每一个w只需要判断往下还是往右填,填的时候 判断颜色是否冲突,自己与所要填的方向的瓷砖是否恰为 wbw 

这样  只需要 遍历遍 ,就可以构造出答案


复杂度 O(n*m) 

细节见代码


x

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include<queue>
using namespace std; 
int dx_down[8]={-1,0,1,2,3,2,1,0};
int dy_down[8]={0,-1,-1,-1,0,1,1,1};
int dx_right[8]={0,1,1,1,0,-1,-1,-1};
int dy_right[8]={-1,0,1,2,3,2,1,0};


int n,m;
char mp[1005][1005];
char vis[1005][1005];
int col=0;
int getcol()
{
	if (col<3)
		col++;
	else
		col=0;
	return col;
}
int check(int tmp,int dir,int x,int y)		//判断往下填的话,颜色tmp是否与周围有冲突
{
	int i;
	if (dir==1)
	{
		for (i=0;i<8;i++)
		{
			int xx=x+dx_down[i];
			int yy=y+dy_down[i];
			if (!(xx>=1&&xx<=n&&yy>=1&&yy<=m)) continue;
			if (vis[xx][yy]=='a'+tmp) return 1;  //need to change col
		}
		return 0;
	}
	else if (dir==2)
	{ 
		for (i=0;i<8;i++)
		{
			int xx=x+dx_right[i];
			int yy=y+dy_right[i];
			if (!(xx>=1&&xx<=n&&yy>=1&&yy<=m)) continue;
			if (vis[xx][yy]=='a'+tmp) return 1;  //need to change col
		}
		return 0;
	}

}
int main()
{ 
	int i,j;
	scanf("%d%d",&n,&m);
	getchar();
	for (i=1;i<=n;i++)
	{
		for (j=1;j<=m;j++)
		{
			scanf("%c",&mp[i][j]);
		}
		getchar();
	}
	int bukeyi=0;
	for (i=1;i<=n;i++)
	{
		for (j=1;j<=m;j++)
		{
			if (mp[i][j]=='.'||vis[i][j]) continue;
			if (mp[i][j]=='w')
			{
				col=getcol();
				int change_times=5;		//如果转了5次颜色 才跳出循环,必然说明不存在合法的颜色可以被填
				if (mp[i][j+1]!='b'||(mp[i][j+1]=='b'&&vis[i][j+1]=='b'))//往下填  //mp[i][j]=='b'不一定往右填,这个b可能是bbb中的b而不是wbw的b
				{
					while(check(col,1,i,j)&&change_times--)  //改变颜色直到合法或者换了4次以上
						col=getcol();
					if (change_times==0) 
					{bukeyi=1;break;}  //找不到合法的颜色
					if (!(mp[i][j]=='w'&&mp[i+1][j]=='b'&&mp[i+2][j]=='w'))	//判断是否存在wbw
					{bukeyi=1;break;}
					mp[i][j]=col+'a';
					mp[i+1][j]=col+'a';
					mp[i+2][j]=col+'a';
					vis[i][j]=col+'a';
					vis[i+1][j]=col+'a';
					vis[i+2][j]=col+'a';
				}
				else //往you填
				{
					while(check(col,2,i,j)&&change_times--)
						col=getcol();
					if (change_times==0) 
					{bukeyi=1;break;}
					if (!(mp[i][j]=='w'&&mp[i][j+1]=='b'&&mp[i][j+2]=='w'))   
					{bukeyi=1;break;}
					mp[i][j]=col+'a';
					mp[i][j+1]=col+'a';
					mp[i][j+2]=col+'a';
					vis[i][j]=col+'a';
					vis[i][j+1]=col+'a';
					vis[i][j+2]=col+'a';
				}
				
			}
			
		}
		if (bukeyi) break;
	}
	
	if (bukeyi)
	{
		printf("NO\n");
		return 0;
	}
	printf("YES\n");
	for (i=1;i<=n;i++)
	{
		for (j=1;j<=m;j++)
		{
			printf("%c",mp[i][j]);
		}
		printf("\n");
	}
	
	return 0;
	
} 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值