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

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

  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. JSP/Servlet开发——第一章 动态网页基础

    1.动态网页:在服务端运行的使用程序语言设计的交互网页 : ●动态网站并不是指具有动画功能的网站,而是指网站内容可根据不同情况动态变更的网站(股票网站),一般情况下动态网站通过数据库进行架构. ●动态 ...

  2. nodejs--http

    http模块主要用到四个方法: 1.Server类 const http = require('http'); let server = new Server(); server.on('reques ...

  3. 微信小程序 提示框延时跳转

    wx.showToast({ title: '成功', icon: 'success', duration: 2000, success:function(){ console.log('haha') ...

  4. STM32(3)——外部中断的使用

    1 .简介 ARM Coetex-M3内核共支持256个中断,其中16个内部中断,240个外部中断和可编程的256级中断优先级的设置.STM32目前支持的中断共84个(16个内部+68个外部),还有1 ...

  5. Django之频率组件

    一.频率简介 为了控制用户对某个url的请求 的频率,比如 ,一分钟以内,只能访问三次 二.自定义频率类,自定义频率规则 自定义的逻辑 (1)取出访问者的ip (2)判断当前ip不在访问字典里,添加进 ...

  6. c#vs连接SQL sever数据库入门操作

    对于需要连接数据库的项目,可以参考的简单初级代码.实现打开数据库,读入数据功能 using System; using System.Collections.Generic; using System ...

  7. springmvc+spring-data-jpa+hibernate环境搭建与配置

    1.JPA诞生的缘由是为了整合第三方ORM框架,建立一种标准的方式,百度百科说是JDK为了实现ORM的天下归一,目前也是在按照这个方向发展,但是还没能完全实现.在ORM框架中,Hibernate是一支 ...

  8. springmvc基础篇—掌握三种控制器

    上一篇文章中我们讲过了处理器的映射,接下来我们来一起学习下springmvc的控制器吧. 首先咱们先创建一个咱们用来测试的实体(model)类: package cn.cfs.springmvc.do ...

  9. IDA动态调试SO文件

    1. 所需工具 IDA Pro 6.6. 安卓SDK工具 2. 模拟器设置 将ida所在目录的dbgsrv文件夹内的android_server文件push到模拟器中. 设置777属性 启动调试服务器 ...

  10. linux开发基本库

    1.ZeroMQ zmq是一个消息队列.可以在进程内.进程间.TCP.多播中,以消息为单位传输数据,而不是socket的字节流.官方主页上有下载.使用.文档,蛮全的. 常用模式有:Request-Re ...