SRM455 Div1 Easy(300) DonutsOnTheGridEasy

DonutsOnTheGridEasy

動的計画法。num(x1,y1,x2,y2)を(x1,y1)-(x2,y2)の長方形が含むドーナツの個数とすると、

num(x1,y1,x2,y2) = min(
 num(x1+1,y1,x2,y2),
 num(x1,y1+1,x2,y2),
 num(x1,y1,x2-1,y2),
 num(x1,y1,x2,y2-1),
 num(x1+1,y1+1,x2-1,y2-1)+1, (この長方形がドーナツの場合)
)

である。

長方形がドーナツかどうかを逐一判定していると時間をオーバーしてしまうので、長方形の各辺について0が連続しているかどうかをあらかじめ調べておく。

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class DonutsOnTheGridEasy
{
public:
    int calc( vector <string> grid );
};

int DonutsOnTheGridEasy::calc( vector <string> grid )
{
    int W = (int)grid.size();
    int H = (int)grid[0].size();

    //  [x1][y1][x2] (x1,y1)-(x2,y1)は0が連続している
    bool hzero[50][50][50];
    //  [x1][y1][y2] (x1,y1)-(x1,y2)は0が連続している
    bool vzero[50][50][50];
    
    for ( int x1=0; x1<W; x1++ )
    for ( int y1=0; y1<H; y1++ )
    {
        hzero[x1][y1][x1] = vzero[x1][y1][y1] = grid[x1][y1] == '0';

        for ( int x2=x1+1; x2<W; x2++ )
            hzero[x1][y1][x2] = grid[x2][y1]=='0' && hzero[x1][y1][x2-1];
        for ( int y2=y1+1; y2<H; y2++ )
            vzero[x1][y1][y2] = grid[x1][y2]=='0' && vzero[x1][y1][y2-1];
    }

    //  [x1][y1][x2][y2] (x1,y1)-(x2,y2)の長方形が含むドーナツ数
    static int num[50][50][50][50];

    for ( int x1=0; x1<W; x1++ )
    for ( int y1=0; y1<H; y1++ )
    for ( int x2=0; x2<W; x2++ )
    for ( int y2=0; y2<H; y2++ )
        num[x1][y1][x2][y2] = 0;

    for ( int w=3; w<=W; w++ )
    for ( int h=3; h<=H; h++ )
    {
        for ( int x1=0; x1<=W-w; x1++ )
        for ( int y1=0; y1<=H-h; y1++ )
        {
            int x2 = x1 + w - 1;
            int y2 = y1 + h - 1;

            int &n = num[x1][y1][x2][y2];

            //  幅・高さどちらかが1小さい長方形が含むドーナツ数
            n = max( n, num[x1+1][y1][x2][y2] );
            n = max( n, num[x1][y1+1][x2][y2] );
            n = max( n, num[x1][y1][x2-1][y2] );
            n = max( n, num[x1][y1][x2][y2-1] );

            //  この長方形自身がドーナツであれば
            //  幅も高さも2小さい長方形が含むドーナツ数+1
            if ( hzero[x1][y1][x2]  &&  hzero[x1][y2][x2]  &&
                 vzero[x1][y1][y2]  &&  vzero[x2][y1][y2] )
                n = max( n, num[x1+1][y1+1][x2-1][y2-1] + 1 );
        }
    }

    return num[0][0][W-1][H-1];
}