上海青少年算法竞赛6月月赛丙组T5题解报告

解法一

一、分析

采用二维数组的前缀和来算。

二、时间复杂度

O(n^4)

三、代码

#include 
using namespace std;

const int maxN = 800 + 5;
int n, m, k, sum[maxN][maxN];
char  a[maxN][maxN];

void input()
{
    cin >> n >> m >> k;
    for(int r=1; r<=n; r++)
    {
        for(int c=1; c<=m; c++)
        {
            cin >> a[r][c];
        }
    }
}

//求二维数组前缀和
void getPreSum()
{
	for(int r=1; r<=n; r++)
    {
        for(int c=1; c<=m; c++)
        {
            sum[r][c] = sum[r-1][c] + sum[r][c-1] - sum[r-1][c-1] + (a[r][c] == '.');
        }
    }
}

int getSum(int r1, int c1, int r2, int c2)
{
    return sum[r2][c2] - sum[r1-1][c2] - sum[r2][c1-1] + sum[r1-1][c1-1];
}

int main()
{
    //freopen("T5.in", "r", stdin);

    input();
    getPreSum();

    const int INF = 2100000000;
    int minArea = INF;

    for(int r1 = 1; r1 <= n; r1++)
    {
        for(int c1 = 1; c1 <= m; c1++)
        {
            for(int r2 = r1; r2 <= n; r2++)
            {
                for(int c2 = c1; c2 <= m; c2++)
                {
                    if(getSum(r1, c1, r2, c2) >= k && (r2 - r1 + 1) * (c2 - c1 + 1) < minArea)
                    {
                        minArea = (r2 - r1 + 1) * (c2 - c1 + 1);
                    }
                }
            }
        }
    }

    if(minArea == INF)
    {
        cout << "No Solution";
    }
    else
    {
        cout << minArea;
    }

    return 0;
}

上海青少年算法竞赛6月月赛丙组T5题解报告_第1张图片

解法二: 尺取法

一、分析

我们可以按照先列后行的顺序来枚举。列有15种情况:
从第1列到第1列(只有一列),从第1列到第2列,从第1列到第3列,从第1列到第4列,从第1列到第5列;
从第2列到第2列,从第2列到第3列,从第2列到第4列,从第2列到第5例;
从第3列到第3列,从第3列到第4列,从第3列到第5列;
从第4列到第4列,从第4列到第5列;
从第5列到第5列。
对于这15种枚举列的情况,再分别枚举行。

以样例2中的数据为例,枚举过程如下:

(一)从第1列到第1列,L = 1, R = 1
(1)从第1行到第1行,up = 1, down = 1,只有一个空座,不够k 个。如图1-a所示。
(2)从第1行到第2行,up = 1, down = 2,只有一个空座,不够k 个。如图1-b所示。
(3)从第1行到第3行,up = 1, down = 3,只有一个空座,不够k 个。如图1-c所示。
(4)从第1行到第4行,up = 1, down = 4,只有一个空座,不够k 个。如图1-d所示。
所以L = 1, R = 1,无论取几行,都没有答案。
上海青少年算法竞赛6月月赛丙组T5题解报告_第2张图片

(二)从第1列到第2列,L = 1, R = 2
(1)从第1行到第1行,up = 1, down = 1,有两个空座,不够k个。如图2-a所示。
(2)从第1行到第2行,up = 1, down = 2,有三个空座,不够k个。如图2-b所示。
(3)从第1行到第3行,up = 1, down = 3,有三个空座,不够k个。如图2-c所示。
(4)从第1行到第4行,up = 1, down = 4,有三个空座,不够k个。如图2-d所示。
上海青少年算法竞赛6月月赛丙组T5题解报告_第3张图片

(三)从第1列到第3列,L = 1, R =3
(1)从第1行到第1行,up = 1, down = 1,有两个空座,不够k个。如图3-a所示。
(2)从第1行到第2行,up = 1, down = 2,有三个空座,不够k个。如图3-b所示。
(3)从第1行到第3行,up = 1, down = 3,有四个空座,不够k个。如图3-c所示。
(4)从第1行到第4行,up = 1, down = 4,有五个空座,够k个。此时的面积为3 * 4 =12。要尝试减少行数来确定有没有更小的面积。如图3-d所示。
(5)从第2行到第4行,up = 2, down = 4,有三个空座,不够k个。因此,从第3行到第4行和从第4行到第4行,都不用再枚举。因为肯定不够k个。如图3-e所示。
上海青少年算法竞赛6月月赛丙组T5题解报告_第4张图片

(四)从第1列到第4列,L = 1, R = 4
(1)从第1行到第1行,up = 1, down = 1,有两个空座,不够k个。如图4-a所示。
(2)从第1行到第2行,up = 1, down = 2,有三个空座,不够k个。如图4-b所示。
(3)从第1行到第3行,up = 1, down = 3,有四个空座,不够k个。如图4-c所示。
(4)从第1行到第4行,up = 1, down = 4,有六个空座,够k个。此时的面积为4 * 4 =16,与上面的12比较,最小的面积仍为12。要尝试减少行数来确定有没有更小的面积。如图4-d所示。
(5)从第2行到第4行,up = 2, down = 4,有四个空座,不够k个。因此,从第3行到第4行和从第4行到第4行,都不用再枚举。因为肯定不够k个。如图4-e所示。
上海青少年算法竞赛6月月赛丙组T5题解报告_第5张图片

(五)从第1列到第5列,L = 1, R = 5
(1)从第1行到第1行,up = 1, down = 1,有两个空座,不够k个。如图5-a所示。
(2)从第1行到第2行,up = 1, down = 2,有三个空座,不够k个。如图5-b所示。
(3)从第1行到第3行,up = 1, down = 3,有五个空座,够k个。面积为3 * 5 = 15,与最小面积12比较,最小值仍为12。不需要继续枚举从第1行到第4行,因为座位肯定够且面积会更大。如图5-c所示。
(4)从第2行到第3行,up = 2, down = 3,有三个空座,不够k个。如图5-d所示。
(5)从第2行到第4行,up = 2, down = 4, 有六个空座,够k个。当前面积为15,最小面积仍为12。如图5-e所示。
(6)从第3行到第4行,up = 3, down = 4,有五个座位,够k个,当前面积为10,最小面积更新为10。如图5-f所示。
(7)从第4行到第4行,up = 4, down = 4,有三个座位,不够k个。如图5-g所示。
上海青少年算法竞赛6月月赛丙组T5题解报告_第6张图片

(六)从第2列到第2列,略

(七)从第2列到第3列,略

(八)从第2列到第4列,略

(九)从第2列到第5列,略

(十)从第3列到第3列,略

(十一)从第3列到第4列,略

(十二)从第3列到第5列,略

(十三)从第4列到第4列,略

(十四)从第4列到第5列,略

(十五)从第5列到第5列,略

二、时间复杂度

O(n^3)

三、代码

#include
using namespace std;

char seat; //'X'表示已被预订,'.'表示空座
const int maxN = 800 + 10;
int n, m, k, totalEmpty, ans = 1e9, a[maxN][maxN];

void getSectionSum(int L, int R)
{
    int emptySeats = 0, up = 1, down = 1;
    for(; up <= n; up++)
    {
        for(; down <= n && emptySeats < k; down++)
        {
            emptySeats += a[down][R] - a[down][L - 1];
        }

        if(emptySeats < k)
        {
            break;
        }

        //down最后又自加了一次,所以down-up不用再+1
        ans = min(ans,(R - L + 1) * (down - up));
        emptySeats -= a[up][R] - a[up][L - 1];
    }
}

int main()
{
    //freopen("T5.in", "r", stdin);
    cin >> n >> m >> k;
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            cin>>seat;
            totalEmpty += (seat == '.'); //总共有多少个空座
            a[i][j] = a[i][j - 1] + (seat == '.');
        }
    }

    if(totalEmpty < k)
    {
        cout<<"No Solution"<<endl;
        return 0;
    }

    for(int L = 1; L <= n; L++)
    {
        for(int R = L; R <= m; R++)
        {
            getSectionSum(L, R);
        }
    }

    cout<<ans<<endl;

    return 0;
}

上海青少年算法竞赛6月月赛丙组T5题解报告_第7张图片

了解中小学信息学竞赛请加微信307591841(QQ同号)

你可能感兴趣的:(上海青少年算法竞赛)