很久之前就很想做的一道题,一直思考到今天才下定决心看题解。这道题中,很关键的一点就在于:如何判断一个点是否在一个多边形内?其实如果计算几何基本功扎实的话,应该是可以很快给出答案的(可惜我完全不行):由一个点向一边引一条射线,判断与多边形相交的边数。若边数是奇数,说明在多边形的内部。在这里贴一篇博文:大佬的博客

  以下想图解一下射线法(与代码判图方式一致)。

  1.图中五角星为一个豆豆。

  2.在转移的时候,我们由\(f[i][j][k] -> f[i][j + 1][k']\) 的转移即为在这两个格子之间链接一条边界线。

 

  3.再转移一下,我们会注意到此时这个豆豆向下引的射线与两条边界线均有交点,但它暂时是被包围的状态,与我们所设的状态矛盾。所以我们规定:只有与箭头头部相交才算做一次。

  4.如果再次出现,次数变成偶数,就不在边界内了:

  通过这几幅图,我们会发现竖直方向的移动不会改变豆豆是否被包围的判定,可以不必重复判断。了解了这一点之后,我们每一次的转移都是在画轮廓线。我们规定状态 \(f[i][j][k]\) 表示当前边界线画到第 \(\left ( i,j \right )\)时,被包围的豆豆状况为 \(k\) 时的最大得分。因为 \(\left ( i,j \right )\) 可以转移到 \(\left ( i,j + 1 \right )\),反之亦然,所以这个转移是不满足拓扑序的。但由于它满足三角形不等式,所以我们使用spfa来转移状态。由于题目规定移动会减少分数,所以不用担心存在正环的问题。

#include <bits/stdc++.h>
using namespace std;
#define maxn 20
#define maxk 6000
#define INF 99999999
int n, m, S, Map[maxn][maxn];
int ans, CNST, val[maxn];
int f[maxn][maxn][maxk];
const int dx[]={, , -, };
const int dy[]={-, , , };
bool vis[maxn][maxn][maxk]; struct node
{
int x, y, num;
node(int xx = , int yy = , int zz = ) { x = xx, y = yy, num = zz; }
}; queue <node> q;
node p[maxn]; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void spfa(int sx, int sy)
{
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
for(int k = ; k < CNST; k ++)
f[i][j][k] = -INF;
q.push(node(sx, sy, )), f[sx][sy][] = , vis[sx][sy][] = ;
while(!q.empty())
{
node now = q.front(); q.pop();
vis[now.x][now.y][now.num] = ;
if(now.x == sx && now.y == sy)
ans = max(ans, f[now.x][now.y][now.num]);
for(int k = ; k < ; k ++)
{
int xx = now.x + dx[k], yy = now.y + dy[k];
if(xx <= || xx > n || yy <= || yy > m || Map[now.x][now.y]) continue;
int num = now.num, Y = max(yy, now.y), del = ;
if(k <= )
{
for(int i = ; i <= S; i ++)
if(p[i].y == Y && p[i].x < xx)
{
num ^= << (i - );
if((num >> i - ) & ) del += val[i];
else del -= val[i];
}
}
if(f[xx][yy][num] < f[now.x][now.y][now.num] + del - )
{
f[xx][yy][num] = f[now.x][now.y][now.num] + del - ;
if(!vis[xx][yy][num]) vis[xx][yy][num] = , q.push(node(xx, yy, num));
}
}
}
} int main()
{
n = read(), m = read(), S = read();
CNST = ( << S) - ;
for(int i = ; i <= S; i ++) val[i] = read();
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
{
char c; cin >> c;
if(c == '#') Map[i][j] = -;
else Map[i][j] = c - '';
if(Map[i][j] >= ) p[Map[i][j]] = node(i, j);
}
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
if(!Map[i][j]) spfa(i, j);
printf("%d\n", ans);
return ;
}

【题解】SCOI2009围豆豆的更多相关文章

  1. 【BZOJ1294】[SCOI2009]围豆豆(动态规划,状压)

    [BZOJ1294][SCOI2009]围豆豆(动态规划,状压) 题面 BZOJ 洛谷 题解 首先考虑如何判断一个点是否在一个多边形内(不一定是凸的),我们从这个点开始,朝着一个方向画一条射线,看看它 ...

  2. 【BZOJ1294】[SCOI2009]围豆豆Bean 射线法+状压DP+SPFA

    [BZOJ1294][SCOI2009]围豆豆Bean Description Input 第一行两个整数N和M,为矩阵的边长. 第二行一个整数D,为豆子的总个数. 第三行包含D个整数V1到VD,分别 ...

  3. [BZOJ1294][SCOI2009]围豆豆Bean 射线法+状压dp+spfa

    1294: [SCOI2009]围豆豆Bean Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 458  Solved: 305[Submit][Sta ...

  4. 洛谷P2566 [SCOI2009]围豆豆(状压dp+spfa)

    题目传送门 题解 Σ(っ °Д °;)っ 前置知识 射线法:从一点向右(其实哪边都行)水平引一条射线,若射线与路径的交点为偶数,则点不被包含,若为奇数,则被包含.(但注意存在射线与路径重合的情况) 这 ...

  5. BZOJ1294: [SCOI2009]围豆豆Bean

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1294 状压dp,dis[s][i][j]表示从(i,j)出发围的状态是s的最短路. 然后判断一 ...

  6. [SCOI2009]围豆豆

    Description Input 第一行两个整数N和M,为矩阵的边长. 第二行一个整数D,为豆子的总个数. 第三行包含D个整数V1到VD,分别为每颗豆子的分值. 接着N行有一个N×M的字符矩阵来描述 ...

  7. 【BZOJ】1294: [SCOI2009]围豆豆Bean

    题解 随机跳题真好玩 这个就是考虑我们怎么判断点在多边形内,就是点做一条射线,穿过了奇数条边 我们只需要记录一个二进制状态表示每个点的射线穿过路径的次数的奇偶性 枚举起点,然后用BFS的方式更新dp状 ...

  8. 洛谷P2566 [SCOI2009]围豆豆(状压dp+计算几何)

    题面 传送门 题解 首先要解决一个问题,就是怎么判断一个点是否在多边形内部 从这个点向某一个方向做一条射线,如果这条射线和多边形的交点为奇数说明在多边形内,否则在多边形外 然而有一些特殊情况,比方说一 ...

  9. BZOJ 1294 [SCOI2009]围豆豆Bean ——计算几何

    显然我们不可能表示出一台路径,因为实在是太复杂了. 所以我们可以记录一下路径对答案的影响,显然路径对答案影响相同的时候,答案更优,所以我们可以用影响来代替路径. 所以我们考虑状压一下所有的豆子有没有被 ...

随机推荐

  1. javascript--BOM的onload事件和onunload事件

    1.onload事件 onload,页面加载后执行,所谓页面加载完成,指页面上所有的元素创建完毕,引用的所有的外部资源(js.css.图片)等下载完毕. 所以onload执行的比较晚,因为如果页面上有 ...

  2. 新知识 HtMl 5

    快要毕业了,即将走向实习岗位,但是这日子过的太无聊了,昨天逃课回宿舍打开电脑想看电影但是没什么好看的,于是上床睡觉了,越躺越无聊,然后爬了起来到学习图书馆找了本HTML5的课本,学习了起来(我感觉ht ...

  3. js-scroll判断页面是向上滚动还是向下滚动

    原理:那当前的scrollTop和之前的scrollTop对比 如果变大了,表示向下滚动(scrollTop值变大): 如果变小了,表示向上滚动(scrollTop值变小). 方法一:js代码: $( ...

  4. docker API 配置与使用

    在网上看到一大堆乱乱七八招的博客,很多都不能用,我根据这些天踩的坑来总结一下吧 首先!怎么配置 docker API 两种方法 在/etc/sysconfig/docker文件里加一行OPTIONS= ...

  5. WinForm webbrowser控件的使用

    webbrowser是一个比较实用的工具,主要用于在winform窗体中嵌入浏览器,达到winform与webform互操作的目的. 先上一个demo,看一下能实现什么效果. private void ...

  6. 消费滚动滴log日志文件(flume监听,kafka消费,zookeeper协同)

    第一步:数据源 手写程序实现自动生成如下格式的日志文件: 15837312345,13737312345,2017-01-09 08:09:10,0360 打包放到服务器,使用如下命令执行,模拟持续不 ...

  7. 2.1 进程控制之fork创建子进程

    fork()函数 目标:熟悉fork创建一个和多个子进程子线程 函数原型:pid_t fork(void); 返回值:成功返回:① 父进程返回子进程的ID(非负) ②子进程返回 0 : 失败返回-1. ...

  8. 杭电 1003 Max Sum (动态规划)

    参考:https://www.cnblogs.com/yexiaozi/p/5749338.html #include <iostream> #include <cstdio> ...

  9. [BZOJ2809][Apio2012]dispatching(左偏树)

    首先对于一个节点以及它的子树,它的最优方案显然是子树下选最小的几个 用左偏树维护出每棵子树最优方案的节点,记录答案 然后它的这棵树可以向上转移给父节点,将所有子节点的左偏树合并再维护就是父节点的最优方 ...

  10. ORB-SLAM (四)tracking单目初始化

    单目初始化以及通过三角化恢复出地图点 单目的初始化有专门的初始化器,只有连续的两帧特征点均>100个才能够成功构建初始化器. ); 若成功获取满足特征点匹配条件的连续两帧,并行计算分解基础矩阵和 ...