有一个矩形区域被划分为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
这个题自己想了很久。。。困于时间和空间。。。一直想枚举两个点,但这样复杂度就超时了。然后如果对每一个点计算其重叠,这样的话空间又会爆。。。
后来和丁神讨论题解之后,终于在第二天才敲出来。。。
这个题的解题思路真的很服。。。
任何一个点不会与超过k^2个点有公共交点。
因此不妨对每个点单独处理这k^2个特殊位置,而其他位置直接取最大值即可。
代码:
#pragma warning(disable:4996)
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <ctime>;
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define INF 0x3fffffff
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
const ll mod = 1e9 + 7;
const int maxn = 105;
int has[maxn][maxn][105];
int con[maxn][maxn][105];
int sz[maxn][maxn],ha_sz[maxn][maxn];
map<pair<int, int>, int>res;
int n, m, k, ans;
int dx[maxn], dy[maxn], val[maxn][maxn];
int flag_cal[100200];
struct no
{
int id;
int val;
}node[100200], node2[100200];
bool cmp(no n1, no n2)
{
return n1.val > n2.val;
}
void input()
{
char tmpc;
int i, j;
scanf("%d%d%d", &n, &m, &k);
scanf("%c", &tmpc);
memset(node, 0, sizeof(node));
memset(node2, 0, sizeof(node2));
memset(sz, 0, sizeof(sz));
memset(ha_sz, 0, sizeof(ha_sz));
memset(flag_cal, 0, sizeof(flag_cal));
for (i = 1; i <= n; i++)
{
for (j = 1; j <= m; j++)
{
scanf("%c", &tmpc);
val[i][j] = tmpc - '0';
int d = (i - 1)*m + j;
node[d].id = d;
}
scanf("%c", &tmpc);
}
for (i = 1; i <= k; i++)
{
scanf("%d%d", &dx[i], &dy[i]);
}
}
void solve()
{
int i, j, h, g;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= m; j++)
{
for (h = 1; h <= k; h++)
{
if (i + dx[h] >= 1 && i + dx[h] <= n&&j + dy[h] >= 1 && j + dy[h] <= m)
{
int pos_x = i + dx[h];
int pos_y = j + dy[h];
int point_flag = (i - 1)*m + j;
sz[pos_x][pos_y]++;
con[pos_x][pos_y][sz[pos_x][pos_y]] = point_flag;
node[point_flag].val += val[pos_x][pos_y];
node2[point_flag].val += val[pos_x][pos_y];
}
}
}
}
sort(node + 1, node + n*m + 1, cmp);
ans = 0;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= m; j++)
{
res.clear();
for (h = 1; h <= k; h++)
{
if (i + dx[h] >= 1 && i + dx[h] <= n&&j + dy[h] >= 1 && j + dy[h] <= m)
{
int pos_x = i + dx[h];
int pos_y = j + dy[h];
int s = sz[pos_x][pos_y];
for (g = 1; g <= s; g++)
{
int x = con[pos_x][pos_y][g] / m + 1;
int y = con[pos_x][pos_y][g] % m;
if (x == i&&y == j)continue;
else
{
int p1_flag = (i - 1)*m + j;
int p2_flag = (x - 1)*m + y;
if (flag_cal[p2_flag])continue;
int s1 = min(p1_flag, p2_flag);
int s2 = max(p1_flag, p2_flag);
res[make_pair(s1, s2)] -= val[pos_x][pos_y];
}
}
}
}
for (h = 1; h <= k*k + 1; h++)
{
int x = node[h].id / m + 1;
int y = node[h].id%m;
int p1_flag = (i - 1)*m + j;
int p2_flag = (x - 1)*m + y;
if (flag_cal[p2_flag])continue;
int s1 = min(p1_flag, p2_flag);
int s2 = max(p1_flag, p2_flag);
if (s1 == s2)continue;
ans = max(ans, res[make_pair(s1, s2)] + node2[p1_flag].val + node[h].val);
if (res[make_pair(s1, s2)] == 0)
break;
}
flag_cal[(i - 1)*m + j] = 1;
}
}
printf("%d\n", ans);
}
int main()
{
//freopen("i.txt", "r", stdin);
//freopen("o.txt", "w", stdout);
int t;
scanf("%d", &t);
while (t--)
{
input();
solve();
}
return 0;
}