1. 程式人生 > 實用技巧 >Luogu洛谷 P3392 塗國旗 題解

Luogu洛谷 P3392 塗國旗 題解

題目

題目連結

Luogu洛谷 P3392 塗國旗

題目大意

某國法律規定,只要一個由 N*M 個小方塊組成的旗幟符合如下規則,就是合法的國旗。(毛熊:阿嚏——)

  • 從最上方若干行(至少一行)的格子全部是白色的;
  • 接下來若干行(至少一行)的格子全部是藍色的;
  • 剩下的行(至少一行)全部是紅色的;

現有一個棋盤狀的布,分成了 N 行 M 列的格子,每個格子是白色藍色紅色之一,小 a 希望把這個布改成該國國旗,方法是在一些格子上塗顏料,蓋住之前的顏色。

小a很懶,希望塗最少的格子,使這塊布成為一個合法的國旗。

輸入

第一行是兩個整數 N,M。

接下來 N 行是一個矩陣,矩陣的每一個小方塊是W(白),B(藍),R(紅)中的一個。

輸出

一個整數,表示至少需要塗多少塊。

樣例輸入

4 5
WRWRW
BWRWB
WRWRW
RWBWR

樣例輸出

11

題解

假設白色的格子行數為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;
}