「第26回オフラインリアルタイムどう書くの問題」をPHPで解く


http://qiita.com/Nabetani/items/8a973a47633558f54ba8
http://nabetani.sakura.ne.jp/hena/ord26tribo/
三種類の境界線

隣接をどう判断するかがポイントでしょう。
いろいろ方法はあると思いますが、まあ単純に隣接リストを持っておくのが楽です。

<?php
    class TRIBO{

        private $pattern1 = [
            // 赤
            '/bc|ef|gh|jk|lm|no|qr|st|uv|wx/',
            // 緑
            '/cd|fg|hi|kl|mn|op|rs|tu|vw|xy/',
        ];
        // 青
        private $pattern2 = [
            '/a.*c/', '/b.*f/', '/d.*h/', '/e.*k/', '/g.*m/',
            '/i.*o/', '/j.*r/', '/l.*t/', '/n.*v/', '/p.*x/'
        ];

        /**
        * 三種類の境界線
        * @param String 「bdelmnouy」みたいな文字列
        * @return String 「5,7,9」みたいな文字列
        */
        public function get($input){
            $ret = array_fill(0, 3, strlen($input));
            // 赤、緑
            foreach($this->pattern1 as $key=>$val){
                $ret[$key] -= preg_match_all($val, $input)*2;
            }
            // 青
            foreach($this->pattern2 as $key=>$val){
                $ret[2] -= preg_match($val, $input)*2;
            }
            return implode(',', $ret);
        }

    }

    // 以下はテスト
    $test = [
        ['bdelmnouy', '5,7,9'],
        ['a', '1,1,1'],
        ['q', '1,1,1'],
        ['t', '1,1,1'],
        ['i', '1,1,1'],
        ['fg', '2,0,2'],
        ['gh', '0,2,2'],
        ['gm', '2,2,0'],
        ['fgh', '1,1,3'],
        ['fghm', '2,2,2'],
        ['fhm', '3,3,3'],
        ['bdfhjprx', '8,8,0'],
        ['abcdfghm', '4,4,0'],
        ['jklmqrst', '0,4,4'],
        ['klmntuvw', '4,0,4'],
        ['abcdefghijklmnopqrstuvwxy', '5,5,5'],
        ['abcdefghijklmnoqrtvwxy', '6,8,4'],
        ['abdefhijklnoprstvwxy', '10,8,4'],
        ['acegikmoqsuwy', '13,13,5'],
        ['bdfhjlnprtvxy', '13,11,1'],
        ['abdegijlnpqsuwy', '15,15,15'],
        ['aefghiqrstuvwxy', '3,3,15'],
        ['cfhkmoqrstuvwxy', '7,7,15'],
        ['cfhkmortvx', '10,10,10'],
        ['no', '0,2,2'],
        ['pwy', '3,3,3'],
        ['iqwy', '4,4,4'],
        ['lopuv', '3,3,5'],
        ['abdjtw', '6,6,6'],
        ['fgpstux', '5,3,5'],
        ['dijlnotv', '6,8,2'],
        ['bdefkmpwx', '5,9,3'],
        ['bfghjlmuwx', '4,8,6'],
        ['befghlopqrw', '5,7,9'],
        ['bfgjklmnqsux', '8,6,8'],
        ['fijklnpqstvwy', '9,9,9'],
        ['abcdfgilmnrsuv', '8,6,6'],
        ['abcdegijklnpruw', '11,11,9'],
        ['efgijkmnopqrtvwx', '6,8,4'],
        ['abcdefghilopqrtwy', '9,9,7'],
        ['abfghklmopqrsuvwxy', '8,6,12'],
        ['abcdeghklmoprstuwxy', '9,7,7'],
        ['abcdehijklmnopqrtwxy', '8,8,6'],
        ['acdefghimnopqrstuvwxy', '7,3,9'],
        ['abcfghijklmnopqrtuvwxy', '6,6,6'],
        ['abcdefghijklmnoqrstuwxy', '5,7,7'],
        ['abcdeghijklmnopqrstuvwxy', '6,6,6'],
    ];

    $tribo = new TRIBO();
    foreach($test as $key=>$data){
        $answer = $tribo->get($data[0]);
        if($answer !== $data[1]){
            print('えらー');
        }
    }

最初は青もpreg_match_all('/a.*c|b.*f|d.*h|e.*k|g.*m|i.*o|j.*r|l.*t|n.*v|p.*x/')一発でいけるかと思ったのですが、

正規表現にマッチすると、そのマッチした文字列の後から 検索が続行されます。

のせいで、'bdfh'に2回マッチしてほしいところ1回しかマッチしませんでした。
そのため青だけ個別に算出しています。残念。

かかった時間は30分程度。
わりと簡単でした。