Topcoder SRM660,DIV1 250,找准突破口,暴力

题意:

给一个n*m的方格,每个方格里有一个数字(范围0~9),现在给一个集合vector_x,和vector_y,分别表示每个点可以覆盖的点集(i+vector_x[],j+vector_y[]),且vector_x和vector_y的大小不超过10。现在让你选两个点,让这两个点覆盖的所有点的权值和最大(被重复覆盖的点,只计算一次)。

范围:0<n,m<=100;

分析:

最暴力的方法:直接枚举两个点,然后求权值之和,复杂度为100*100*100*100*10,肯定超时。

题目中数据范围较小的条件,很可能是题目的突破口,vector_x和vector_y的范围最大为10,我们将从这里突破。

首先看一下一个点最多可以被多少个不同的点覆盖,因为vector_x和vector_y的范围都是10,所以可以得知,每个点最多可以被10个不同的点覆盖。

在方格中选一个点(i,j),把他覆盖的10个点当作一个状态,那么最多有多少状态和他有交集,可以大致判断为100个。

题目转化为从100*100个状态中,选择两个状态,权值最大。

做法:

首先预处理出100*100个状态,然后从大到小排序,则前101个状态中,肯定有不相交的状态,然后只需枚举前101个状态,然后判断,求解出最大值。

复杂度:预处理:100*100*10,排序:100*100*log(100*100),求解:101*101*10

//这题思路较好,这里我只写出了思路分析,代码取自:http://blog.csdn.net/madaidao/article/details/46373655
#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;
    }


};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值