题意: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)覆盖的点有交集的所有点,并修改他们的权值。那么我们只需要用一些数据结构维护所有点能覆盖的点的点权和,并能在较快的复杂度里面求解最大值,就能解决问题。