java游戏挖土吃钻石_[HG]钻石游戏diamond 题解

题面

钻石游戏(diamond)

问题描述:

一个\(M\)行\(N\)列的棋盘,里面放了\(M \times N\)个各种颜色的钻石。

每一次你可以选择任意两个相邻的颜色不同的钻石,进行交换。两个格子相邻的定义是两个格子有一条公共边。

每次交换的分值为通过这次交换后能够形成的最大矩形的面积,具体请见样例。

跟传统的钻石游戏不太一样的是,交换后钻石不会消除。现在告诉你每一次操作,

请输出每一次所能得到的分值。

问题输入:

第一行二个整数\(M,N\)。

接下来\(M\)行\(N\)列,表示第\(I\)行第\(J\)列的钻石的颜色\((1-9)\)。

第\(M+2\)行有一个正整数\(P\),表示钻石交换的次数。

接下来\(P\)行,每行四个正整数\(x1,y1,x2,y2\),\(1 \leq x1,x2 \leq M,1 \leq y1,y2 \leq N\),表示交换\((x1,y1)\)和\((x2,y2)\)的钻石。

保证\((x1,y1),(x2,y2)\)的颜色不相同,并且其必定相邻。

问题输出:

\(P\)行,输出每次交换得到的分值

题解

这道题目的主要失误在于对数据范围估计错误,其实暴力模拟加小优化后的最劣复杂度为\(\Theta(n^2 \times q)\)

约为\(2500\)万,是可以通过的。

这题的暴力很简单,对于每次交换,向外扩展,然后在从内至外枚举,

然后在枚举内部继续往另一个方向扩展,即可计算矩形面积。

稍加分情况讨论即可,代码稍长,但是基本可以复制。

代码

#include

#include

using namespace std;

int read(){

int x = 0; int zf = 1; char ch = ' ';

while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();

if (ch == '-') zf = -1, ch = getchar();

while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;

}

//define n the row number, m the col number.

int n, m;

int _max;

int mp[505][505];

int getL(int x, int y, int val){

int cnt = 0;

for (int i = y; i && mp[x][i] == val && (y - i) <= _max; --i)

++cnt;

return cnt;

}

int getR(int x, int y, int val){

int cnt = 0;

for (int i = y; i <= m && mp[x][i] == val && (i - y) <= _max; ++i)

++cnt;

return cnt;

}

int getU(int x, int y, int val){

int cnt = 0;

for (int i = x; i && mp[i][y] == val && (x - i) <= _max; --i)

++cnt;

return cnt;

}

int getD(int x, int y, int val){

int cnt = 0;

for (int i = x; i <= n && mp[i][y] == val && (i - x) <= _max; ++i)

++cnt;

return cnt;

}

int main(){

n = read(), m = read();

for (int i = 1; i <= n; ++i)

for (int j = 1; j <= m; ++j)

mp[i][j] = read();

int p = read();

while (p--){

int x1 = read(), y1 = read(), x2 = read(), y2 = read();

if (x1 == x2){

if (y1 > y2)

swap(x1, x2), swap(y1, y2);

}

else if (x1 > x2)

swap(x1, x2), swap(y1, y2);

swap(mp[x1][y1], mp[x2][y2]);

if (x1 == x2){

int ans = 0;

_max = 505; int upper = getL(x1, y1, mp[x1][y1]);

int minu = 505, mind = 505;

for (int i = 1; i <= upper; ++i){

int j = y1 - i + 1;

minu = min(minu, getU(x1, j, mp[x1][y1]));

mind = min(mind, getD(x1, j, mp[x1][y1]));

_max = min(_max, max(minu, mind));

if ((minu + mind - 1) * i > ans)

ans = (minu + mind - 1) * i;

}

minu = 505, mind = 505;

_max = 505, upper = getR(x2, y2, mp[x2][y2]);

for (int i = 1; i <= upper; ++i){

int j = y2 + i - 1;

minu = min(minu, getU(x2, j, mp[x2][y2]));

mind = min(mind, getD(x2, j, mp[x2][y2]));

_max = min(_max, max(minu, mind));

if ((minu + mind - 1) * i > ans)

ans = (minu + mind - 1) * i;

}

printf("%d\n", ans);

}

else{

int ans = 0;

_max = 505; int upper = getU(x1, y1, mp[x1][y1]);

int minl = 505, minr = 505;

for (int i = 1; i <= upper; ++i){

int j = x1 - i + 1;

minl = min(minl, getL(j, y1, mp[x1][y1]));

minr = min(minr, getR(j, y1, mp[x1][y1]));

_max = min(_max, max(minl, minr));

if ((minl + minr - 1) * i > ans)

ans = (minl + minr - 1) * i;

}

minl = 505, minr = 505;

_max = 505, upper = getD(x2, y2, mp[x2][y2]);

for (int i = 1; i <= upper; ++i){

int j = x2 + i - 1;

minl = min(minl, getL(j, y2, mp[x2][y2]));

minr = min(minr, getR(j, y2, mp[x2][y2]));

_max = min(_max, max(minl, minr));

if ((minl + minr - 1) * i > ans)

ans = (minl + minr - 1) * i;

}

printf("%d\n", ans);

}

}

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值