【bzoj 2241】【SDOI2011】打地鼠 题解&代码(C++)

题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=2241
题解:
接近于暴力,在暴力之上加一些优化,首先我们发现如果 r×c的锤子不能达到要求时,(2×r)×c以及r×(2×c)就不能达到要求,以此类推(3×r)×c。。。。的锤子都不行,那么我们可以预先处理一下r=1或c=1的情况,最后枚举r,c的时候,可以剪枝,还有我们发现总的地鼠数 sum 必须是锤子面积的倍数,否则不可能将所有的地鼠打掉,以此再判断即可。
代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
int sum,n,m,f[105][105],tt[105][105],hang[105],lie[105];
bool pan(int r,int c)
{
    for (int i=1;i<=m;i++)
    for (int j=1;j<=n;j++)
    tt[i][j]=f[i][j];

    for (int i=1;i<=m;i++)
    for (int j=1;j<=n;j++)
    {
        if (tt[i][j]!=0)
        {
            if (i+r-1<=m && j+c-1<=n)
            {
                int tmp=tt[i][j];
                for (int x=i;x<=i+r-1;x++)
                for (int y=j;y<=j+c-1;y++)
                {
                    tt[x][y]-=tmp;
                    if (tt[x][y]<0)
                    return 0;
                }
            }
            else
            return 0;
        }
    }
    return 1;
}
int main()
{
    scanf("%d%d",&m,&n);
    for (int i=1;i<=m;i++)
    for (int j=1;j<=n;j++)
    {
        scanf("%d",&f[i][j]);
        sum+=f[i][j];
    }
    for (int i=2;i<=m;i++)
    if (hang[i]==0)
    {
        if (!pan(i,1))
        for (int j=i;j<=m;j+=i)
        hang[j]=-1;
    }
    for (int i=2;i<=n;i++)
    if (lie[i]==0)
    {
        if (!pan(1,i))
        for (int j=i;j<=n;j+=i)
        lie[j]=-1;
    }
    int ans=1e9+7;
    for (int i=m;i>=1;i--)
    for (int j=n;j>=1;j--)
    if (hang[i]==-1||lie[j]==-1) continue;
    else if (sum%(i*j)==0 && sum/(i*j)<ans)
    {
        if (pan(i,j))
        {
            int tmpa=sum/(i*j);
// cout<<i<<' '<<j<<' '<<tmpa<<endl;
            ans=min(ans,tmpa);
        }
    }
    printf("%d\n",ans);
}

你可能感兴趣的:(优化,暴力)