Loading

雅礼国庆集训 day1 T3 画作

题面

题目下载

算法

猜测最优解是
每一次染色都是之前染色的子集且颜色相反(证明不会)

所以可以逆向思维(注意直接逆向不成立)
最后一次染色一定在一个四连通块中, 之前的染色一定是后一次染色的超集
把每个颜色的连通块缩点, 例如
pAGtZrT.png
每次将一个点(即原图中的连通块)染色成反色, 相当于加入了与之连接的反色连通块, 变成了一个新的点, 也就是图上的边

于是对于每一个点, bfs求其到最远点的最短路径长度即为答案
时间复杂度 \(O(r^2 c^2)\)


首先考虑复习

分析问题, 要求从全 \(0\) 的矩阵变为给定的目标 \(01\) 矩阵

套路
  • 定义操作, 要求把 aba \to b
    • 逆向思维, 把 bb 拆成 aa
      • STL\rm{STL} 维护
    • 考虑操作是否能构造出单位操作, 在用单位操作的性质去做题 ((一般是到了哪里就不能操作了))
    • 打印操作方法
      • 考虑一种构造策略
    • 约束仅存在于操作顺序/每个元素的状态上
      • 考虑对约束顺序/状态建图判环
    • 可以考虑找可逆性 : 有了这个性质就可以把问题简化成变换到同一种形式
    • 直接正向处理
      • 构造方式
        • 往往应该把选择权留到后面去

比较显然的是, 我们需要把问题转化成从给定矩阵到全 \(0\) 矩阵的操作

模拟一下操作找性质, 不难发现操作应当是先操作子集, 然后操作自己, 这样下来的步数最少
考虑一些大的样例

00000000000
11100111100
10101100111
10101100010
11101111011
00111011011
11001111111

如果我把它形式化
pEszWgH.png
让我们一起找这个图的最优解

发现我们只需将一小块涂黑, 然后整个黑色就连起来的, 一起归白即可

提示我们可以把每个颜色的连通块缩点, 例如
pAGtZrT.png
每次将一个点(即原图中的连通块)染色成反色, 相当于加入了与之连接的反色连通块, 变成了一个新的点, 也就是图上的边
于是对于每一个点, bfs求其到最远点的最短路径长度即为答案

代码

传统 ctj

//T3 paint

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

const int maxn=55,inf=0x3f3f3f3f;
int n,m,mx[4]={0,1,0,-1},my[4]={1,0,-1,0},dis[maxn*maxn],id[maxn][maxn],q[maxn*maxn*2],l,r,cnt,ix[maxn*maxn],iy[maxn*maxn],ans;
char ch[maxn];
bool mp[maxn][maxn],vis[maxn*maxn];

int max(int a,int b)
{
	if (a>b)
		return a;
	return b;
}

int min(int a,int b)
{
	if (a<b)
		return a;
	return b;
}

int bfs(int u)
{
	int i,v,x,y,tx,ty;
	l=maxn*maxn,r=l-1;
	q[++r]=u;
	vis[u]=1;
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[u]=1;
	while (l<=r)
	{
		u=q[l++];
		x=ix[u],y=iy[u];
		for (i=0;i<=3;i++)
		{
			tx=x+mx[i],ty=y+my[i];
			v=id[tx][ty];
			if (tx<1||tx>n||ty<1||ty>m||vis[v])
				continue;
			if (mp[tx][ty]==mp[x][y])
			{
				dis[v]=dis[u];
				q[--l]=v;
				vis[v]=1;
			}
			else
			{
				dis[v]=dis[u]+1;
				q[++r]=v;
				vis[v]=1;
			}
			if (mp[tx][ty]&&dis[v]>=ans)
				return inf;
		}
	}
	int tmp=0;
	for (i=1;i<=cnt;i++)
		if (mp[ix[i]][iy[i]])
			tmp=max(tmp,dis[i]);
	return tmp;
}

int main()
{
	freopen("paint.in","r",stdin);
	freopen("paint.out","w",stdout);
	int i,j;
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++)
	{
		scanf("%s",ch+1);
		for (j=1;j<=m;j++)
		{
			mp[i][j]=(ch[j]-48);
			id[i][j]=++cnt;
			ix[cnt]=i,iy[cnt]=j;
		}
	}
	ans=inf;
	for (i=1;i<=n;i++)
		for (j=1;j<=m;j++)
			ans=min(ans,bfs(id[i][j]));
	printf("%d\n",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

总结

结论题猜测大法
注意染色, 四连通块问题一般可以建模成图, 然后在处理

posted @ 2024-10-08 08:25  Yorg  阅读(17)  评论(0)    收藏  举报