P3392 涂国旗
题目描述
题目描述
某国法律规定,只要一个由 N \times MN×M 个小方块组成的旗帜符合如下规则,就是合法的国旗。(毛熊:阿嚏——)
- 从最上方若干行(至少一行)的格子全部是白色的;
- 接下来若干行(至少一行)的格子全部是蓝色的;
- 剩下的行(至少一行)全部是红色的;
现有一个棋盘状的布,分成了 NN 行 MM 列的格子,每个格子是白色蓝色红色之一,小 a 希望把这个布改成该国国旗,方法是在一些格子上涂颜料,盖住之前的颜色。
小a很懒,希望涂最少的格子,使这块布成为一个合法的国旗。
输入格式
第一行是两个整数 N,MN,M。
接下来 NN 行是一个矩阵,矩阵的每一个小方块是
W
(白),B
(蓝),R
(红)中的一个。输出格式
一个整数,表示至少需要涂多少块。
输入输出样例
输入 #1复制
4 5 WRWRW BWRWB WRWRW RWBWR
输出 #1复制
11
说明/提示
样例解释
目标状态是:
WWWWW BBBBB RRRRR RRRRR
一共需要改 1111 个格子。
数据范围
对于 100%100% 的数据,N,M \leq 50N,M≤50。
算法求解
分析
枚举涂w的底边和涂b的底边即可
剩下的部分都涂r
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 60;
int n, m;
char g[N][N];
int res = 0;
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
cin >> g[i][j];
}
}
int wst = 1, wend;
int res = 3000;
int bst, bend, rst, rend;
// 枚举涂w的终点行wend 1 -> n-2
for(wend = wst; wend <= n-2; wend++)
{
int tmpa = 0;
// wst -> wend 图 w
for(int i = wst; i <= wend; i++)
{
for(int j = 1; j <= m; j++)
{
if(g[i][j] != 'W') tmpa++;
}
}
// 枚举涂b的终点行bend wend+1 -> n-1
bst = wend + 1, bend;
for(bend = bst; bend <= n-1; bend++)
{
int tmpb = 0;
for(int i = bst; i <= bend; i++)
{
for(int j = 1; j <= m; j++)
{
if(g[i][j] != 'B') tmpb++;
}
}
// 最后全涂成r
for(int i = bend+1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(g[i][j] != 'R') tmpb++;
}
}
res = min(res, tmpa + tmpb);
}
// res = min(res, tmp);
}
cout << res << endl;
return 0;
}
这个代码写的不是很好,可以直接枚举涂w的底边和涂b的底边即可更清晰一点
用下面的做法更清楚一点
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 60;
int n, m;
char g[N][N];
int res = 0;
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
cin >> g[i][j];
}
}
int wend, bend;
// 涂白的底边
int res = 3000;
for(int wend = 1; wend <= n-2; wend++)
{
// 涂 蓝的底边
for(int bend = wend+1; bend <= n-1; bend++)
{
int tmp = 0;
// 涂白
for(int i = 1; i <= wend; i++)
for(int j = 1; j <= m; j++)
if(g[i][j] != 'W') tmp++;
// 涂蓝
for(int i = wend+1; i <= bend; i++)
for(int j = 1; j <= m; j++)
if(g[i][j] != 'B') tmp++;
// 涂红
for(int i = bend+1; i <= n; i++)
for(int j = 1; j <= m; j++)
if(g[i][j] != 'R') tmp++;
res = min(res, tmp);
}
}
cout << res << endl;
return 0;
}
时间复杂度
参考文章
https://www.luogu.com.cn/problem/solution/P3392
数据范围这么小(n,m<=50)(n,m<=50),果断暴力枚举,代码简单难度低。搜索什么的用不着啦!
那么问题来了:枚举这么呢?
先抛张图:
我们只要枚举白与蓝、蓝与红的边界(如上图a和b),再统计三个区域里总共有多少格子需要涂改颜色,用一个变量来记录最优的答案(即需要涂改的格子数最少),不断更新,最后输出就OK了qwq.
时间复杂度O(n^3m)O(n3∗m*)(感谢 @万弘 的提醒,之前写错了).
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
2021-02-28 牛客寒假算法训练营1-D