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

srupのメモ帳

競プロで解いた問題や勉強したことを記録していくメモ帳

aoj 0534 - Chain

AOJ 全探索

問題

問題概要

一列バージョンのぷよぷよみたいな感じ。好きな場所の色を一箇所変えることができ、それを行うことにより最も多くボールを消せる場合を求める問題。

解法

まずすべての玉の色を変えて全探索する。そして色を変えた前後で同じ色の数をカウントする。カウントした数が4以上ならその部分の玉を消せる。そのあとは同じ色の部分だった両側の数字が同じであれば、さらに玉を消せる可能性があるので、同じ操作を繰り返す。

ミス

変数n_tmpを作らずに、n -= tmpを行い、while(r < n && v[r] == color)を行っていたので、バグらせた。

コード

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define rep(i,n) for(int i=0;i<(n);i++)
#define reps(i,f,n) for(int i=(f);i<(n);i++)
static const int INF = 1e9;

int erace(int n, vector<int> v, int num, int c){//ボールの個数 ボール(数字)の配列 色を変えた場所 変えた色の番号
    int n_tmp = n;//残っているボールの番号
    int l = num;//色変えた場所の番号
    int r = num + 1;
    int color = c;//変えた場所の数字の番号(色)
    while(1){
        int cnt = 0;//同じ数字が連続している数
        //左側に何個同じ色が連続しているか
        while(0 <= l && v[l] == color){
            cnt++;
            l--;//左端を伸ばす
        }
        //右側に何個同じ色が連続しているか
        while(r < n && v[r] == color){
            cnt++;
            r++;//右端を伸ばす
        }
        if(cnt >= 4){
            n_tmp -= cnt;//連続した数の分を消す
            if(v[l] == v[r]){
                color = v[l];//次に消える色を更新する
            }
            else break;//消した後の両サイドが同じ色でなければ、それ以上消えることはない
        }else{
            break;//4つ消えなければ、それ以上消えることはない
        }
    }
    return n_tmp;
}

int main(void){
    while(1){
        int n; scanf("%d", &n);
        if(n == 0) return 0;
        vector<int> v(n);
        rep(i, n) scanf("%d", &v[i]);
        int ans = INF;//初期化
        //全探索
        rep(i, n){//色を変えるとこの番号
            int tmp = v[i];
            //色を変える
            reps(j, 1, 4){//色を変える
                if(tmp == j) continue;
                v[i] = j;
                ans = min(ans, erace(n, v, i, j));
            }
            v[i] = tmp;//ボールの色を元に戻す
        }
        printf("%d\n", ans);
    }
    return 0;
}