题解:CF37E Trial for Chief
题目分析
题意
给一张全白的图,每次可以将一个四联通块染黑或染白,求转化到目标最少染色次数。
分析
考虑倒着想,由目标染回原图。
易得倒着染回去和正着染的最少染色次数相同。
所以我们考虑从最后的图入手。
考虑从某一个点 \((i,j)\) 开始染色。
尝试进行建图。
在同样的颜色间转移的代价是 \(0\)。
如果颜色不同,就需要至少进行一次染色,所以代价是 \(1\)。
建图跑最短路即可。
每次跑完后用距离最大的黑点更新答案。(因为原图是白色,所以只统计黑点)
并且默认一开始需染一次色,所以 \(dis_s=1\)。
发现边权只有 \(0\) 和 \(1\)。
可以考虑使用 0-1 BFS 求最短路。(其实用 0-1BFS 求的话可以不用建图)
时间复杂度 \(O((nm)^2)\)。
Code
#include<bits/stdc++.h>
using namespace std;
#define maxn 52
string tmp;
int mp[maxn][maxn];
#define pos(i, j) (m*((i)-1)+j)
#define chk(i, j) ((i)&&(j)&&(i<=n)&&(j<=m))
vector<pair<int, int> > e[maxn*maxn];
deque<int> dq;
int dis[maxn*maxn];
int bfs(int x, int n, int m)
{
memset(dis, 0x3f, sizeof dis);
dis[x]=1;
dq.emplace_back(x);
while(!dq.empty())
{
auto u=dq.front();
dq.pop_front();
for(auto [v, w]:e[u])
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(w) dq.emplace_back(v);
else dq.emplace_front(v);
}
}
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(mp[i][j]) ans=max(ans, dis[pos(i, j)]);
return ans;
}
int main()
{
int n, m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>tmp;
for(int j=1;j<=m;j++)
mp[i][j]=(tmp[j-1]=='B');
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(chk(i-1, j)) e[pos(i, j)].emplace_back(pos(i-1, j), mp[i][j]!=mp[i-1][j]);
if(chk(i+1, j)) e[pos(i, j)].emplace_back(pos(i+1, j), mp[i][j]!=mp[i+1][j]);
if(chk(i, j-1)) e[pos(i, j)].emplace_back(pos(i, j-1), mp[i][j]!=mp[i][j-1]);
if(chk(i, j+1)) e[pos(i, j)].emplace_back(pos(i, j+1), mp[i][j]!=mp[i][j+1]);
}
int ans=numeric_limits<int>::max();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans=min(ans, bfs(pos(i, j), n, m));
cout<<ans;
}

浙公网安备 33010602011771号