原题地址

看上去非常复杂, 实际上是这一系列最简单的一步,本质上是个搜索过程,相比于前一道题,可以不用策略三,而且题目的数据规模超级小,所以暴力搜索就能过。

把尚未确定的点放在一个unsettled列表里,然后依次枚举每个点的情况:是地雷or不是地雷

优化方案一即:每次枚举后,使用规则一、规则二对列表里剩下的点进行判断,如果能直接判断出是不是地雷的就立即设置了,这样剩下的枚举位就少了。当然回溯的时候记得把这些拓展出来的也要一并回溯。

优化方案二即:周围已知地雷数少的点优先枚举。(这个优化没做)

啰啰嗦嗦写了一大堆代码,WA了一次,原来是判断规则一规则二的时候单纯用8去做判断了,而一个点周围邻居点个数可能不是8。

代码:

 #include <iostream>
#include <vector>
#include <cstring>
#include <cstdlib> using namespace std; struct point {
int r;
int c;
int v;
point(int _r, int _c) : r(_r), c(_c) {};
point(int _r, int _c, int _v) : r(_r), c(_c), v(_v) {};
bool operator==(const point &o) {return o.r == r && o.c == c;}
bool operator!=(const point &o) {return o.r != r || o.c != c;}
}; #define SIZE 40 int N, M;
int field[SIZE][SIZE];
int ans[SIZE][SIZE];
int unset[SIZE][SIZE];
vector<point> unsettled; bool valid(point &p) {
return p.r >= && p.r < N && p.c >= && p.c < M;
} vector<point> neighbors(point p) {
vector<point> res; for (int i = -; i < ; i++) {
for (int j = -; j < ; j++) {
point q(i + p.r, j + p.c);
if (valid(q) && q != p)
res.push_back(q);
}
} return res;
} void merge(point p) {
if (ans[p.r][p.c] == - || ans[p.r][p.c] == p.v)
ans[p.r][p.c] = p.v;
else
ans[p.r][p.c] = -;
} int around(point p, int s) {
vector<point> nbs = neighbors(p);
int res = ; for (auto q : nbs) {
if (field[q.r][q.c] >= && s == ) {
res++;
continue;
}
else
res += unset[q.r][q.c] == s ? : ;
} return res;
} bool check(point p) {
vector<point> nbs = neighbors(p);
int mine = around(p, );
int not_mine = around(p, );
return (mine <= field[p.r][p.c] && field[p.r][p.c] + not_mine <= nbs.size());
} bool check() {
bool is_ok = true; for (auto p : unsettled) {
if (!is_ok)
break;
vector<point> nbs = neighbors(p);
for (auto q : nbs) {
if (field[q.r][q.c] >= && !check(q)) {
is_ok = false;
break;
}
}
} return is_ok;
} void extend() {
bool over = false; while (!over) {
over = true;
for (auto p : unsettled) {
vector<point> nbs = neighbors(p);
for (auto q : nbs) {
if (field[q.r][q.c] < )
continue; vector<point> os = neighbors(q);
int mine = around(p, );
int not_mine = around(q, ); if (field[q.r][q.c] + not_mine == os.size()) {
for (auto o : os) {
if (o.v == -) {
over = false;
o.v = ;
unset[o.r][o.c] = ;
}
}
}
if (mine == field[q.r][q.c]) {
for (auto o : os) {
if (o.v == -) {
over = false;
o.v = ;
unset[o.r][o.c] = ;
}
}
}
}
}
}
} void solve(int pos) {
if (pos >= unsettled.size()) {
for (auto p : unsettled) {
merge(p);
}
return;
} if (unsettled[pos].v != -) {
solve(pos + );
unsettled[pos].v = -;
unset[unsettled[pos].r][unsettled[pos].c] = -;
return;
} for (int i = ; i < ; i++) {
unsettled[pos].v = i;
unset[unsettled[pos].r][unsettled[pos].c] = i;
if (!check())
continue;
extend();
solve(pos + );
}
unsettled[pos].v = -;
unset[unsettled[pos].r][unsettled[pos].c] = -;
} int main() {
int n; cin >> n;
while (n--) {
cin >> N >> M;
memset(ans, -, SIZE * SIZE * sizeof(int));
memset(unset, -, SIZE * SIZE * sizeof(int));
unsettled.clear();
for (int i = ; i < N; i++) {
for (int j = ; j < M; j++) {
cin >> field[i][j];
if (field[i][j] < )
unsettled.push_back(point(i, j, -));
}
} solve(); int mine = ;
int not_mine = ; for (auto p : unsettled) {
mine += (ans[p.r][p.c] == ? : );
not_mine += (ans[p.r][p.c] == ? : );
} cout << mine << " " << not_mine << endl; } return ;
}

hihoCoder#1120 小Hi小Ho的惊天大作战:扫雷·三的更多相关文章

  1. hihoCoder 1114 小Hi小Ho的惊天大作战:扫雷·一 最详细的解题报告

    题目来源:小Hi小Ho的惊天大作战:扫雷·一 解题思路:因为只要确定了第一个是否有地雷就可以推算出后面是否有地雷(要么为0,要么为1,如果不是这两个值就说明这个方案行不通),如果两种可能中有一种成功, ...

  2. hiho #1114 : 小Hi小Ho的惊天大作战:扫雷·一

    #1114 : 小Hi小Ho的惊天大作战:扫雷·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 故事背景:密室.监视器与充满危机的广场 “我们还是循序渐进,先来考虑这 ...

  3. hihoCoder#1119 小Hi小Ho的惊天大作战:扫雷·二

    原题地址 没有复杂算法,就是麻烦,写起来细节比较多,比较考验细心,一次AC好开心. 代码: #include <iostream> #include <vector> #inc ...

  4. hihoCoder#1114 小Hi小Ho的惊天大作战:扫雷·一

    原题地址 回溯+搜索 枚举每个位置上能否放地雷,当第i个位置枚举完成后,第i-1个位置的情况就确定了,此时,检查第i-1个位置是否满足要求,即左右间隔为1的范围内地雷数是否等于申明数字,如果满足条件, ...

  5. ACM学习历程—Hihocoder编程之美测试赛B题 大神与三位小伙伴(组合数学 )

    时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给你一个m x n (1 <= m, n <= 100)的矩阵A (0<=aij<=10000),要 ...

  6. 【转】HTML5的小知识点小集合

    html5的小知识点小集合 html5知识   1.  Doctype作用?标准模式与兼容模式各有什么区别? (1).<!DOCTYPE>声明位于位于HTML文档中的第一行,处于<h ...

  7. html5的小知识点小集合

      html5的小知识点小集合 html5知识   1.  Doctype作用?标准模式与兼容模式各有什么区别? (1).<!DOCTYPE>声明位于位于HTML文档中的第一行,处于< ...

  8. 微信小程序即将开放申请?微信小论坛小程序专场16日或可见分晓

    9月22号微信小程序内测至今已经好一段时间了,首批只开放了200个名额,没拿到内测资格的朋友早就等到心急了.就在刚刚,微信公开课宣布微信小论坛小程序专场即将在11月16号举行,微信公众平台小程序会在当 ...

  9. 如何获取微信小店小程序的AppID

    2017年11月16日,微信有一个重磅的宣布:为了帮商家在微信内快速开店,方便商家和用户之间沟通,所有认证公众号,可快速创建微信小店小程序.这个改变是否能给微信小店带来新的生机?还需要时间的考验.微信 ...

随机推荐

  1. Vue自定义过滤器格式化数字三位加一逗号

    <template> <div class="index-compont"> <div class="totalCount"> ...

  2. VS打包后生成快捷方式:目标指向错误、Icon图标分辨率有误问题解决方案

    1.目标指向错误: 在安装***.msi文件后,对快捷方式-->右键-->属性: 发现目标并非指exe文件. 于是我新建了一个快捷方式,将目标-->指向exe文件,位置Ctrl+v. ...

  3. Android学习备忘笺02Fragment

    Android中Fragment可以将UI界面分成多个区块,一般静态或动态添加Fragment. 01.新建Fragment实例 一个Fragment实例包括两个部分:类对象和布局文件(可视化部分). ...

  4. SSM Note

    1.获取项目的绝对路径:${pageContext.request.contextPath } 2.销毁session:session.invalidate(); 3.控制器接收前端参数时,参数名要与 ...

  5. AJPFX关于代码块的总结

    代码块:        {                执行语句;        }(1) 当出现在局部位置时, 为局部代码块.        局部位置: 如语句块中, 函数中, 构造代码块中, 静 ...

  6. for循环的两种写法哪个快

    结果如下: 其实工作中,也没有这么多数据需要遍历,基本上用foreach

  7. hihocoder offer收割编程练习赛12 C 矩形分割

    思路: 模拟,深搜. 实现: #include <iostream> #include <cstdio> #include <string> using names ...

  8. core\stm32f10x.h(244): error: #67: expected a "}"

  9. Python3 动手自己写谷歌翻译

    本篇为实现谷歌翻译的功能,在编写的时候以为只是一个接口的问题. 没想到的是每次翻译都会触发一次JS的执行,在请求参数中生成一个tk. 文中tk的实现是复用的网上大神的代码生成tk. 好了,不说了直接看 ...

  10. UVALive 4128 Steam Roller 蒸汽式压路机(最短路,变形) WA中。。。。。

    题意: 给一个由n*m个正方形格子组成的矩形,其中每个格子的边都是可以走的,长度给定,规定:如果在进入该路前需要拐弯,或者走完该路需要拐弯,都是需要付出双倍距离的(每条路最多算2倍).问从起点到终点的 ...