Topcoder SRM660 DIV1 250 Coversta(暴力枚举)

题意:n*m的网格图,每个网格有一个权值,范围为(0到9)。有一个x数组和y数组,这两个数组大小相等且<=10。如果我们选择一个点( i , j ) 。则可以覆盖点 (i+x[k], j+y[k]),0<=k<=x数组的大小。问选择两个点,被覆盖的点的点权和最大为多少?n<=100,m<=100。

方法一:仔细观察题目,x数组的大小最大为10,我们可以从这里下手。由于x的数组大小只有10,与点( i,j )覆盖了相同点的点不超过100个。 我们枚举选择的第一个点( i,j ),然后再枚举另一个点,由于与其有交集的点不超过100个,那么我们只需枚举能覆盖点权和最大的100个点即可(不包括(i,j))。不难发现,对于枚举的第一个点,我们也只需枚举点权和最大的前100个点即可。复杂度O(100*100*10)。

代码如下:

#line 4 "Coversta.cpp"
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
#define OUT(x) cout << #x << ": " << (x) << endl
#define SZ(x) ((int)x.size())
#define FOR(i, n) for (int i = 0; i < (n); ++i)
const int inf=0x3fffffff;
using namespace std;
typedef long long LL;
struct node
{
    int u,v;
    int val;
    node(){}
    node(int uu,int vv,int vall)
    {
        u=uu,v=vv,val=vall;
    }
}b[11000];
bool use[110][110];
bool cmp(node x,node y)
{
    return x.val>y.val;
}
class Coversta
{
public:
    int place(vector <string> a, vector <int> x, vector <int> y)
    {
        int n=a.size(),m=a[0].size();
        int l=x.size();
        int num=0;
        int i,j,k;
        int ix,dx,dy;
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
                ix=0;
                for(k=0;k<l;k++)
                {
                    dx=i+x[k];
                    dy=j+y[k];
                    if(dx>=0&&dx<n&&dy>=0&&dy<m)
                    {
                        ix+=a[dx][dy]-'0';
                    }
                }
                b[num++]=node(i,j,ix);
            }
        }
        int ans=-inf;
        sort(b,b+num,cmp);
        memset(use,false,sizeof(use));
        for(i=0;i<min(num,100);i++)
        {
            for(k=0;k<l;k++)
            {
                dx=b[i].u+x[k];
                dy=b[i].v+y[k];
                if(dx>=0&&dx<n&&dy>=0&&dy<m)
                    use[dx][dy]=true;
            }
            for(j=i+1;j<min(num,100);j++)
            {
                if(b[i].val+b[j].val<=ans)
                    break;
                ix=b[i].val;
                for(k=0;k<l;k++)
                {
                    dx=b[j].u+x[k];
                    dy=b[j].v+y[k];
                    if(dx>=0&&dx<n&&dy>=0&&dy<m)
                    {
                        if(!use[dx][dy])
                        {
                            ix+=a[dx][dy]-'0';
                        }
                    }
                }
                ans=max(ans,ix);
            }
            for(k=0;k<l;k++)
            {
                dx=b[i].u+x[k];
                dy=b[i].v+y[k];
                if(dx>=0&&dx<n&&dy>=0&&dy<m)
                    use[dx][dy]=false;
            }
        }
        return ans;
    }


};


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor

方法二:还是由于与点(i,j)覆盖的点有交集的点不超过100个。首先枚举选择的第一个点( i,j ) ,那么此时我们需要求解剩余点覆盖的点(不包括已经被覆盖的点)的点权和的最大值 。我们可以预处理出每个点覆盖的点的点权和。我们可以O(100)的复杂度求出与点(i,j)覆盖的点有交集的所有点,并修改他们的权值。那么我们只需要用一些数据结构维护所有点能覆盖的点的点权和,并能在较快的复杂度里面求解最大值,就能解决问题。


你可能感兴趣的:(ACM,topcoder)