2011 ACM/ICPC 北京赛区现场赛解题:GemAnd Prince

来源:互联网 发布:最强nba主网络断开 编辑:程序博客网 时间:2024/05/16 17:34

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4090

模拟+搜索:对于每一个局面,用bfs穷举出下一步所有可能存在的消除宝石的方法,每发现这样的一个方法就dfs进入下一层。

(即通过floodfill的方法进行bfs,每得到一个大小大于2的连通块的时候就dfs递归深入下去。这样可以让下面的剪枝得到很好的效果,可以将搜索树的size大大减小。)

剪枝:对于每一个局面,记录它通过之前的步骤已经得到的分数,然后维护它还可能得到的最大的分数(比如已经得到了120分,还有5个红色宝石,4个蓝色宝石,2个黑色宝石,那此局面可能得到的分数一定不超过120+5*5+4*4),通过用这个分数与当前已经得到的最大分数进行比较来进行剪枝。对于大多数数据这个剪枝能剪掉99.9%的节点,所以有时可以跑过10*9的数据,但是这个剪枝也是不稳定的,存在不少数据能把它卡掉。不过对于题目的最大上限8*8,这个剪枝已经足够了。

代码:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <cmath>using namespace std;int n, m, k;int mp[10][10];bool v2[10][10];int xx[8] = {0, 0, 1, -1, 1, -1, 1, -1};int yy[8] = {1, -1, 0, 0, 1, -1, -1, 1};int cnt, ans, sum;bool in(int x,  int y){if (x <= n && x >= 1 && y <= m && y >= 1)  return true;return false;}void dfs(int x, int y, int tt[10][10], int p, bool vv[10][10]){vv[x][y] = 1;cnt++;for (int i = 0; i < 8; ++i){if (in(x + xx[i], y + yy[i]) && !vv[x + xx[i]][y + yy[i]] && tt[x + xx[i]][y + yy[i]] == p){dfs(x + xx[i], y + yy[i], tt, p, vv);}}}void dfs2(int x, int y, int tt[10][10], int p){v2[x][y] = 1;tt[x][y] = 0;for (int i = 0; i < 8; ++i){if (in(x + xx[i], y + yy[i]) && !v2[x + xx[i]][y + yy[i]] && tt[x + xx[i]][y + yy[i]] == p){dfs2(x + xx[i], y + yy[i], tt, p);}}}void move(int tt[10][10]){int i, j, a[10], cc;for (i = 1; i <= 8; ++i)  a[i] = 0;for (i = 1; i <= m; ++i){cc = 0;for (j = 1; j <= n; ++j)  if (tt[j][i] > 0)  {  a[++cc] = tt[j][i];  }for (j = 1; j <= n - cc; ++j)  tt[j][i] = 0;for (j = 1; j <= cc; ++j){tt[j + n - cc][i] = a[j];}}for (j = 1; j <= m; ++j){cc = 0;for (i = 1; i <= n; ++i)  if (tt[i][j] > 0) cc++;a[j] = cc;}int tp[10];for (i = 1; i <= n; ++i){int tc = 0;for (j = 1; j <= m; ++j)  if (a[j] == 0)  {  continue;  }  else  {  tp[++tc] = tt[i][j];  }for (j = 1; j <= tc; ++j)  tt[i][j] = tp[j];for (j = tc + 1; j <= m; ++j)  tt[i][j] = 0;}}void click(int tt[10][10], int s, int *a, int x, int y){int i, j;int ta[7], tmp[10][10];bool vv[10][10];int ts = s;for (i = 1; i <= k; ++i){if (a[i] >= 3)  ts += a[i] * a[i];}if (ts < ans) return;for (int ii = 1; ii <= n; ++ii){for (int jj = 1; jj <= m; ++jj){vv[ii][jj] = 0;v2[ii][jj] = 0;tmp[ii][jj] = tt[ii][jj];}}if (x != 0 && y != 0)  dfs2(x, y, tmp, tmp[x][y]);move(tmp);for (i = 1; i <= n; ++i){for (j = 1; j <= m; ++j){if (!vv[i][j] && tmp[i][j] > 0){for (int ii = 1; ii <= k; ++ii)  ta[ii] = a[ii];cnt = 0;dfs(i, j, tmp, tmp[i][j], vv);if (cnt >= 3){ta[tmp[i][j]] -= cnt;click(tmp, s + cnt * cnt, ta, i, j);}}}}ans = max(ans, s);}int main(){int i, j, a[7];while (scanf("%d%d%d", &n, &m, &k) != EOF){memset(a, 0, sizeof(a));memset(v2, 0, sizeof(v2));for (i = 1; i <= n; ++i){for (j = 1; j <= m; ++j){scanf("%d", &mp[i][j]);if (mp[i][j] > 0)  a[mp[i][j]]++;}}ans = 0;click(mp, 0, a, 0, 0);printf("%d\n", ans);}}


原创粉丝点击