BZOJ 1294 围豆豆 题解
题目
是不是平时在手机里玩吃豆豆游戏玩腻了呢?最近MOKIA手机上推出了一种新的围豆豆游戏,大家一起来试一试吧。
游戏的规则非常简单,在一个N×M的矩阵方格内分布着D颗豆子,每颗豆有不同的分值Vi。游戏者可以选择任意一个方格作为起始格,每次移动可以随意的走到相邻的四个格子,直到最终又回到起始格。最终游戏者的得分为所有被路径围住的豆豆的分值总和减去游戏者移动的步数。矩阵中某些格子内设有障碍物,任何时刻游戏者不能进入包含障碍物或豆子的格子。游戏者可能的最低得分为0,即什么都不做。
注意路径包围的概念,即某一颗豆在路径所形成的多边形(可能是含自交的复杂多边形)的内部。下面有两个例子:

第一个例子中,豆在路径围成的矩形内部,所以豆被围住了。第二个例子中,虽然路径经过了豆的周围的8个格子,但是路径形成的多边形内部并不包含豆,所以没有围住豆子。
布布最近迷上了这款游戏,但是怎么玩都拿不了高分。聪明的你决定写一个程序来帮助他顺利通关。
输入格式
第一行两个整数\(N\)和\(M\),为矩阵的边长。
第二行一个整数\(D\),为豆子的总个数。
第三行包含\(D\)个整数\(V_1\)到\(V_D\),分别为每颗豆子的分值。
接着\(N\)行有一个\(N \times M\)的字符矩阵来描述游戏矩阵状态,0表示空格,#表示障碍物。而数字1到9分别表示对应编号的豆子。
输出格式
仅包含一个整数,为最高可能获得的分值。
样例输入
3 8
3
30 -100 30
00000000
010203#0
00000000
样例输出
38
说明/提示
50%的数据满足\(1 \le D \le 3\)。
100%的数据满足\(1 \le D \le 9,1 \le N, M \le 10,-10000 \le V_i \le 10000\)。
题解
\(N,M\)的范围都很小,所以可以直接暴力广搜,但是保存状态不能直接用数组,处理起来会很麻烦,应该状态压缩.
我重点讲一下怎么判断一个点是否在多边形内:
先说结论,从某点向外做射线,若该射线与多边形相交了奇数次,该点就在该多边形的内部,否则在外部
下面证明
我们设想这个射线是从这个点出发的一条路径,在我们沿着这个路径走的过程中,可以得到以下结论:
由于射线无限长,而多边形有限,所以射线最后一次与多边形相交一定是从多边形内部交到外部,由此可得,倒数第二次相交(如果有的话)一定是从外部交到内部.
所以每交一次内外状态翻转,而最后的状态又是在外部,所以当交奇数次,最开始状态和最后的状态相反,即在内部,同理当交偶数次,最开始在外部.
这道题中规定从该点向右的射线为判定线,当你搜索路径奇数次相交于点\(i\)的判定线,点\(i\)在路径多边形内部,反之在外部.
当这个点的状态从在外部变成在内部,总分数加上这个点的分值;当这个点的状态从在内部变成在外部,总分数减去这个点的分值,注意搜索过程中每走一步总分值要减一.
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 15, M = 1050;
int n, m, d, f[N][N][M], vis[N][N], in[N][N][M], x[N], y[N], bean[N], ans, dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
struct node {int x, y, status;};
queue<node> q;
void solve(int fx, int fy) {
memset(f, 0, sizeof(f)), memset(in, 0, sizeof(in));
f[fx][fy][0] = 0, q.push((node){fx, fy, 0});
while (!q.empty()) {
node now = q.front();
q.pop();
for (int k = 0; k < 4; k++) {
int nx = now.x + dx[k], ny = now.y + dy[k];
if (nx <= 0 || nx > n || ny <= 0 || ny > m || vis[nx][ny]) continue;
int status = now.status, score = f[now.x][now.y][now.status] - 1; // 注意减去移动的1步
if (k < 2) { // k<2时,上下移动才可能穿过右射线
for (int i = 1; i <= d; i++) { //枚举豆子
if (x[i] != min(nx, now.x) || y[i] > ny) continue; //没穿过这个豆子的右射线 or 经过这个豆子的左边
if (status >> i - 1 & 1) score -= bean[i];
else score += bean[i];
status ^= (1 << (i - 1)); //改变经过次数奇偶性
}
}
if (!in[nx][ny][status])
in[nx][ny][status]=1, f[nx][ny][status] = score, q.push((node){nx, ny, status});
}
}
for (int i = 0; i < (1 << d); i++)
if (in[fx][fy][i]) ans = max(ans, f[fx][fy][i]);
}
int main() {
scanf("%d%d%d", &n, &m, &d);
for (int i = 1; i <= d; i++) scanf("%d", &bean[i]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
char c;
scanf(" %c", &c);
if (c == '#') vis[i][j] = -1;
else x[c - '0'] = i, y[c - '0'] = j, vis[i][j] = c - '0';
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (!vis[i][j]) solve(i, j);
printf("%d\n", ans);
return 0;
}
BZOJ 1294 围豆豆 题解的更多相关文章
- 【BZOJ1294】[SCOI2009]围豆豆(动态规划,状压)
[BZOJ1294][SCOI2009]围豆豆(动态规划,状压) 题面 BZOJ 洛谷 题解 首先考虑如何判断一个点是否在一个多边形内(不一定是凸的),我们从这个点开始,朝着一个方向画一条射线,看看它 ...
- 【BZOJ1294】[SCOI2009]围豆豆Bean 射线法+状压DP+SPFA
[BZOJ1294][SCOI2009]围豆豆Bean Description Input 第一行两个整数N和M,为矩阵的边长. 第二行一个整数D,为豆子的总个数. 第三行包含D个整数V1到VD,分别 ...
- [BZOJ1294][SCOI2009]围豆豆Bean 射线法+状压dp+spfa
1294: [SCOI2009]围豆豆Bean Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 458 Solved: 305[Submit][Sta ...
- 洛谷P2566 [SCOI2009]围豆豆(状压dp+spfa)
题目传送门 题解 Σ(っ °Д °;)っ 前置知识 射线法:从一点向右(其实哪边都行)水平引一条射线,若射线与路径的交点为偶数,则点不被包含,若为奇数,则被包含.(但注意存在射线与路径重合的情况) 这 ...
- BZOJ 1003 物流运输 题解 【SPFA+DP】
BZOJ 1003 物流运输 题解 Description 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的 ...
- BZOJ 1191 超级英雄 Hero 题解
BZOJ 1191 超级英雄 Hero 题解 Description 现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的多少获得不同数目的奖品或奖金 ...
- SCOI 2009 围豆豆(状压DP)
SCOI 2009 围豆豆 题目描述 是不是平时在手机里玩吃豆豆游戏玩腻了呢?最近MOKIA手机上推出了一种新的围豆豆游戏,大家一起来试一试吧. 游戏的规则非常简单,在一个N×M的矩阵方格内分布着D颗 ...
- BZOJ1294 洛谷P2566 状态压缩DP 围豆豆
传送门 题目描述 是不是平时在手机里玩吃豆豆游戏玩腻了呢?最近MOKIA手机上推出了一种新的围豆豆游戏,大家一起来试一试吧游戏的规则非常简单,在一个N×M的矩阵方格内分布着D颗豆子,每颗豆有不同的分值 ...
- 【BZOJ】1294: [SCOI2009]围豆豆Bean
题解 随机跳题真好玩 这个就是考虑我们怎么判断点在多边形内,就是点做一条射线,穿过了奇数条边 我们只需要记录一个二进制状态表示每个点的射线穿过路径的次数的奇偶性 枚举起点,然后用BFS的方式更新dp状 ...
随机推荐
- java正则匹配 指定内容以外的 内容
今天,遇到一个需要 匹配出 指定内容以外的 内容的需求. 乍一看,需求貌视很简单啊,直接上 非贪婪模式的 双向零宽断言(有的资料上也叫 预搜索.预查.环视lookaround): 比如,我要匹配 串内 ...
- TCP/IP三次握手协议
一.简介 三次握手协议指的是在发送数据的准备阶段,服务器端和客户端之间需要进行三次交互,OSI参考模型中的网络层,在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一 ...
- Javascript模块化编程(转自阮一峰的网络日志)(备忘)
http://www.ruanyifeng.com/blog/2012/10/javascript_module.html
- Android使用OkHttp实现登录注册功能
客户端 在客户端,这里将登录和注册放在了同一个界面,在账号和密码两个EditText中输入内容后,按下LOGIN按钮,进行登录:按下REGISTER按钮,进行注册. 在写代码之前,先添加OkHttp的 ...
- 记录一次Flink作业异常的排查过程
最近2周开始接手apache flink全链路监控数据的作业,包括指标统计,业务规则匹配等逻辑,计算结果实时写入elasticsearch. 昨天遇到生产环境有作业无法正常重启的问题,我负责对这个问题 ...
- Java多线程与并发基础
CS-LogN思维导图:记录专业基础 面试题 开源地址:https://github.com/FISHers6/CS-LogN 多线程与并发基础 实现多线程 面试题1:有几种实现线程的方法,分别是什么 ...
- 有趣的程序分析之C
1. 下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题: 1 2 3 4 int square( volatile int *ptr ) { retur ...
- 甜咸粽子党大战,Python爬取淘宝上的粽子数据并进行分析
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 爬虫 爬取淘宝数据,本次采用的方法是:Selenium控制Chrome浏览 ...
- Redis设置并查看最大连接数
在 Redis2.4 中,最大连接数是被直接硬编码在代码里面的,而在2.6版本中这个值变成可配置的. maxclients 的默认值是 10000,你也可以在 redis.conf 中对这个值进行修改 ...
- Spark HA搭建
正文 下载Spark版本,这版本又要求必须和jdk与hadoop版本对应. http://spark.apache.org/downloads.html tar -zxvf 解压到指定目录,进入con ...