雅礼国庆集训 day1 T3 画作
题面
算法
猜测最优解是
每一次染色都是之前染色的子集且颜色相反(证明不会)
所以可以逆向思维(注意直接逆向不成立)
最后一次染色一定在一个四连通块中, 之前的染色一定是后一次染色的超集
把每个颜色的连通块缩点, 例如

每次将一个点(即原图中的连通块)染色成反色, 相当于加入了与之连接的反色连通块, 变成了一个新的点, 也就是图上的边
于是对于每一个点, bfs求其到最远点的最短路径长度即为答案
时间复杂度 \(O(r^2 c^2)\)
首先考虑复习
分析问题, 要求从全 \(0\) 的矩阵变为给定的目标 \(01\) 矩阵
套路
- 定义操作, 要求把
- 逆向思维, 把 拆成
- 用 维护
- 考虑操作是否能构造出单位操作, 在用单位操作的性质去做题 一般是到了哪里就不能操作了
- 打印操作方法
- 考虑一种构造策略
- 约束仅存在于操作顺序/每个元素的状态上
- 考虑对约束顺序/状态建图判环
- 可以考虑找可逆性 : 有了这个性质就可以把问题简化成变换到同一种形式
- 直接正向处理
- 构造方式
- 往往应该把选择权留到后面去
- 构造方式
- 逆向思维, 把 拆成
比较显然的是, 我们需要把问题转化成从给定矩阵到全 \(0\) 矩阵的操作
模拟一下操作找性质, 不难发现操作应当是先操作子集, 然后操作自己, 这样下来的步数最少
考虑一些大的样例
00000000000
11100111100
10101100111
10101100010
11101111011
00111011011
11001111111
发现我们只需将一小块涂黑, 然后整个黑色就连起来的, 一起归白即可
提示我们可以把每个颜色的连通块缩点, 例如

每次将一个点(即原图中的连通块)染色成反色, 相当于加入了与之连接的反色连通块, 变成了一个新的点, 也就是图上的边
于是对于每一个点, 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;
}
总结
结论题猜测大法
注意染色, 四连通块问题一般可以建模成图, 然后在处理


浙公网安备 33010602011771号