有一个矩形区域被划分为N行M列的网格,每个格子里有一定数量的资源并记录在矩阵val中,坐标(x,y)位置上资源量为val[x][y],其val中每个元素的值为0~9的整数。如果你在某个网格(a,b)上造一座保护塔,那么你可以占领K个网格中的资源,这K个格子分别是(a+dx[1],b+dy[1]),(a+dx[2],b+dy[2]),...,(a+dx[K],b+dy[K]),注意(a,b)这格本身可能未必会被占领。现在你能建造不超过2个塔,问最多能占领多少资源?一个网格被多个塔占领时其资源只计算一次。另外如果计算的位置(a+dx[i],b+dy[i])在网格外,则不贡献任何资源。
Input
多组测试数据,第一行一个整数T,表示测试数据数量,1<=T<=5 每组测试数据有相同的结构构成: 每组数据第一行三个整数N,M,K,其中2<=N,M<=100,1<=K<=10。 之后会有N行,每行M个元素,表示val矩阵。每个元素为0~9,占一个字符,元素间没空格。 再接下来有K行,每行两个整数dx[i]与dy[i],其中-(N-1)<=dx[i]<=N-1,-(M-1)<=dy[i]<=(M-1).
Output
每组数据一行输出,即可占领的最大资源总量。
Input示例
3 2 2 2 11 11 0 0 0 1 2 2 2 11 11 0 0 1 1 2 2 1 15 61 0 0
Output示例
4 3 11
孔炤
(题目提供者)
C++的运行时限为:1000 ms ,空间限制为:131072 KB
示例及语言说明请按这里
允许其他 AC 的用户查看此代码,分享代码才能查看别人的代码并有机会获得勋章
题解:最浅显的做法是枚举两个保护塔,然后求解,复杂度是O(n^2*m^2*k^2)。。。。算了吧
呢还能怎么搞哇。真的是难倒我了,想了半天也没有合适的姿势,只好看了发题解。
然后看了:http://blog.csdn.net/qwb492859377/article/details/51088928大牛的博客,才有了思路。
具体就是枚举一个保护塔的位置,然后处理出来所有和这个保护塔有所冲突的位置以及不冲突的位置。
有所冲突的位置不会超过k^2个,所以暴力就行,不冲突的位置我们可以考虑用RMQ。。。
总复杂度为O(n*m*k^3)....可以过。。。
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<time.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<functional>
using namespace std;
typedef long long ll;
#define inf 1000000000
#define mod 1000000007
#define maxn 20005
#define PI 3.1415926
#define lowbit(x) (x&-x)
#define eps 1e-9
char s[105][105];
int n, m, k, a[maxn][15], val[maxn], q[maxn];
int w[maxn], vis[105][105], b[maxn / 100], c[maxn / 100];
int f(int x, int y)
{
return (x - 1)*m + y;
}
void RMQ(int len)
{
int i, j;
for (i = 1;i <= len;i++)
a[i][0] = w[i];
for (j = 1;(1 << j) <= len;j++)
for (i = 1;i + (1 << j) - 1 <= len;i++)
a[i][j] = max(a[i][j - 1], a[i + (1 << (j - 1))][j - 1]);
}
int findmax(int l, int r)
{
int len = 0;
while ((1 << (len+1)) <= r - l + 1)
len++;
return max(a[l][len], a[r - (1 << len) + 1][len]);
}
int solve()
{
int ans = 0, i, j, h, t;
for(i=1;i<=n;i++)
for (j = 1;j <= m;j++)
{
int mx = 0, cnt = 0, id = f(i, j);
for (h = 1;h <= k;h++)
{
int dx = i + b[h];
int dy = j + c[h];
if (dx<1 || dx>n || dy<1 || dy>m)
continue;
vis[dx][dy] = id;
for (t = 1;t <= k;t++)
{
int x = dx - b[t];
int y = dy - c[t];
if (x<1 || x>n || y<1 || y>m)
continue;
q[++cnt] = f(x, y);
}
}
q[++cnt] = 0;
q[++cnt] = n*m + 1;
sort(q + 1, q + cnt + 1);
cnt = unique(q + 1, q + cnt + 1) - q - 1;
for (h = 1;h < cnt;h++)
if (q[h] + 1 <= q[h + 1] - 1)
mx = max(mx, findmax(q[h] + 1, q[h + 1] - 1));
for (h = 2;h < cnt;h++)
{
int x = (q[h] - 1) / m + 1;
int y = (q[h] - 1) % m + 1;
int sum = w[f(x, y)];
for (t = 1;t <= k;t++)
{
int dx = x + b[t];
int dy = y + c[t];
if (dx<1 || dx>n || dy<1 || dy>m)
continue;
if (vis[dx][dy] == id)
sum -= s[dx][dy]-'0';
}
mx = max(mx, sum);
}
ans = max(ans, mx + w[id]);
}
return ans;
}
int main(void)
{
int T, i, j, h;
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &n, &m, &k);
for (i = 1;i <= n;i++)
for (j = 1;j <= m;j++)
vis[i][j] = w[f(i, j)] = 0;
for (i = 1;i <= n;i++)
scanf("%s", s[i] + 1);
for (i = 1;i <= k;i++)
scanf("%d%d", &b[i], &c[i]);
for(i=1;i<=n;i++)
for (j = 1;j <= m;j++)
{
int id = f(i, j);
for (h = 1;h <= k;h++)
{
int dx = i + b[h];
int dy = j + c[h];
if (dx<1 || dx>n || dy<1 || dy>m)
continue;
w[id] += s[dx][dy] - '0';
}
}
RMQ(n*m);
printf("%d\n", solve());
}
}