読者です 読者をやめる 読者になる 読者になる

プロコン初心者日記

解いたプロコンの問題を保存しておくためのブログ

【yukicoder】No.179 塗り替え

yukicoder 競技プログラミング 全探索

yukicoderさんの問題

No.179 塗り分け - yukicoder

参考書

プログラミングコンテストチャレンジブック [第2版]

難しさ(初心者目線)

・考え方***

・実装***

・面白さ***

問題概要

・白と黒で塗られたマスがある
・黒いマスを赤か青に塗り替えたい
・この時、赤いマスを平行移動させると青いマスにちょうど重なるようにしたい
・白いマス".“と黒いマス”#“が与えられるので、上記の条件で塗り替えられるかどうか求めよ

方針

・塗り替えられていない黒いマスについて(dx, dy)移動した先に塗り替えられていない黒マスがあればOK ・全探索

コード

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <bitset>
using namespace std;

#define ll         long long
#define PI         acos(-1.0)
#define FOR(I,A,B) for(int I = (A); I < (B); ++I)

//方針
//塗り替えられていない黒いマスについて(dx, dy)移動した先に塗り替えられていない黒マスがあればOK
//全探索

int main(){
    int H, W;
    cin >> H >> W;
    //#or.を保存
    vector<string> mass(H);
    FOR(i, 0, H) cin >> mass[i];
    //塗り替えたかどうか
    bool isPainted[H][W];
    FOR(i, 0, H) FOR(j, 0, W) isPainted[i][j] = false;
    //移動した先のマスを塗り替えられたかどうか
    bool check = false;
    FOR(dy, -H, H){
        FOR(dx, -W, W){
            //移動量が0の時は飛ばす
            if(dy==0 && dx==0) continue;

            //塗り替えたかどうかの情報初期化
            FOR(i, 0, H) FOR(j, 0, W) isPainted[i][j] = false;

            //注目するマスをFORでまわす
            FOR(z, 0, (H-1)*W+W){
                int y = z / W;
                int x = z % W;

                //塗り替えられていない#のマスについて
                if(mass[y][x]=='#' && isPainted[y][x]==false){
                    isPainted[y][x]=true;

                    //移動先が範囲外ならbreak移動量変えてやり直し
                    if(y+dy<0 || y+dy>=H || x+dx<0 || x+dx>=W){
                        check = false;
                        break;
                    }

                    //移動先が塗り替えられていない#ならOK
                    if(mass[y+dy][x+dx]=='#' && isPainted[y+dy][x+dx]==false){
                        isPainted[y+dy][x+dx]=true;
                        check = true;
                    }

                    //塗り替えられていたらbreak移動量変えてやり直し
                    else{
                        check = false;
                        break;
                    }
                }
            }

            //falseでなければ全て矛盾なかったということ
            if(check){
                cout << "YES" << endl;
                return 0;
            }
        }
    }
    cout << "NO" << endl;
}