Luogu洛谷 P3392 涂国旗 题解
题目
题目链接
题目大意
某国法律规定,只要一个由 N*M 个小方块组成的旗帜符合如下规则,就是合法的国旗。(毛熊:阿嚏——)
- 从最上方若干行(至少一行)的格子全部是白色的;
- 接下来若干行(至少一行)的格子全部是蓝色的;
- 剩下的行(至少一行)全部是红色的;
现有一个棋盘状的布,分成了 N 行 M 列的格子,每个格子是白色蓝色红色之一,小 a 希望把这个布改成该国国旗,方法是在一些格子上涂颜料,盖住之前的颜色。
小a很懒,希望涂最少的格子,使这块布成为一个合法的国旗。
输入
第一行是两个整数 N,M。
接下来 N 行是一个矩阵,矩阵的每一个小方块是W(白),B(蓝),R(红)中的一个。
输出
一个整数,表示至少需要涂多少块。
样例输入
4 5
WRWRW
BWRWB
WRWRW
RWBWR
样例输出
11
题解
共有2种做法。
假设白色的格子行数为w, 蓝色格子行数为b, 那么红色格子行数就是r = n-w-b,而且 1 <= w, b, r <=n-2。
枚举w与b,当w与b确定,r就可以算出来。
难点是如何确定当前是枚举w还是枚举b。我这里是通过确定w是否为0来确定枚举w还是b。
then show the code.
#include <cstdio>
const int maxn = 50*50+5;
int n, m, tot, w, b, r, a[3], mintot = maxn;
char sheet[55][55];
// cur表示当前已经确定了几行的颜色
void dfs(int cur){
//统计当前w,b,r确定的状态下 需要涂改的格子数量
if(cur == n){
tot = 0;
for(int i=0; i<w; i++)
for(int j=0; j<m; j++)
if(sheet[i][j] != 'W') tot++;
for(int i=w; i<w+b; i++)
for(int j=0; j<m; j++)
if(sheet[i][j] != 'B') tot++;
for(int i=w+b; i<n; i++)
for(int j=0; j<m; j++)
if(sheet[i][j] != 'R') tot++;
if(tot < mintot) mintot = tot;
//当w为0 说明应该枚举w
}else if(!w){
for(int i=1; i<=n-2; i++){
w = i;
dfs(cur+w);
w = 0;
}
//当b为0 说明应该枚举b
}else if(!b){
for(int i=1; i<=n-w-1; i++){
b = i;
if(w+b > n-1) break;
dfs(cur+b);
b = 0;
}
//当确定了w与b 则通过计算确定r
}else if(!r){
r = n - w - b;
dfs(cur+r);
r = 0;
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++)
scanf("%s", sheet[i]);
dfs(0);
printf("%d\n", mintot);
return 0;
}
第2种做法比较简单,直接枚举即可。。。。。。
Then show the code.
#include <cstdio>
#include <algorithm>
using namespace std;
char sheet[55][55];
int n, m, minn=2500;
int main(){
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
scanf("%s", &sheet[i][1]);
for(int w=1; w<=n-2; w++) //枚举白色行数
for(int b=1; b<=n-w-1; b++){ //枚举蓝色行数
int r = n-w-b, cnt=0; //算出红色行数
//求需要涂色多少块
for(int i=1; i<=w; i++)
for(int j=1; j<=m; j++)
if(sheet[i][j] != 'W') cnt++;
for(int i=w+1; i<=w+b; i++)
for(int j=1; j<=m; j++)
if(sheet[i][j] != 'B') cnt++;
for(int i=w+b+1; i<=n; i++)
for(int j=1; j<=m; j++)
if(sheet[i][j] != 'R') cnt++;
minn = min(minn, cnt);
}
printf("%d", minn);
return 0;
}
不忘初心方得始终