题目传送门

题解 Σ(っ °Д °;)っ

前置知识

射线法:从一点向右(其实哪边都行)水平引一条射线,若射线与路径的交点为偶数,则点不被包含,若为奇数,则被包含。(但注意存在射线与路径重合的情况)

这里是一篇专门介绍此法的博客:射线法

思路

(这次的博客有点粗糙,有空我再加点解释注释啥的)

数据很小,我们直接暴力之。但情况很多,一一枚举不现实,故状压之:以一个二进制串代表各个豆豆的获得情况(1即获得,0即不获得)。这就是我们的状态(即代码里的condition)。我们把所有(所有起点,所有状态)的状态答案都暴力出来,再根据题意找最优即可。

ps:不要吐槽我的变量名为啥这么长,我这也是为了尽量通俗易懂一点嘛。

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=11,maxm=1<<11;
#define ll long long
ll f[maxn][maxn][maxm],a[maxn],val[maxm];//val[i]中的i是状态
ll ans=-99999999;
bool vis[maxn][maxn][maxm];
int n,m,d,x[maxn],y[maxn],num[maxn][maxn];//x[],y[],分别储存了豆豆的坐标
int dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1};//第一位数dx[0],dy[0]是无意义的
struct node{
int started,ended,condition;
node();
node(int x,int y,int z){
started=x,ended=y,condition=z;
}
};
int Change(int last_x,int last_y,int next_x,int next_y,int last_condition){
int next_conditon=last_condition;//下一步状态由上一步转换而来
for(int i=1;i<=d;i++){//枚举豆豆
//判断是是否上下运动,为了避免上面所说的重合情况,只有上下运动我们才更新状态
if(((last_x==x[i]&&next_x<x[i])||(last_x<x[i]&&next_x==x[i]))&&next_y>y[i])//我们走一步可能让一个豆豆进圈或者出圈
next_conditon=next_conditon^(1<<(i-1));//把二进制的第i位(从右到左哦)取反
}
return next_conditon;
}
queue<node> q;
void Spfa(int fx,int fy){//我们找出每种状态下的最短路,再枚举判断最优答案
memset(f,0x3f,sizeof(f));//和普通的spfa一样一样的
memset(vis,0,sizeof(vis));
f[fx][fy][0]=0;
q.push(node(fx,fy,0));
while(!q.empty()){
node t=q.front();q.pop();
int u=t.started,v=t.ended,last_condition=t.condition;
vis[u][v][last_condition]=0;
for(int k=1;k<=4;k++){//向四周遍历
int xx=u+dx[k],yy=v+dy[k];
if(xx<=0||yy<=0||xx>n||yy>m||num[xx][yy]!=0) continue;//判断越不越界以及点能不能走
int next_condition;
next_condition=Change(u,v,xx,yy,last_condition);//更新状态
if(f[u][v][last_condition]+1<f[xx][yy][next_condition]){//更新最短路
f[xx][yy][next_condition]=f[u][v][last_condition]+1;
if(vis[xx][yy][next_condition]==0){
vis[xx][yy][next_condition]=1;
q.push(node(xx,yy,next_condition));
}
}
}
}
for(int i=0;i<(1<<d);i++){//枚举状态找最优答案
ans=max(ans,val[i]-f[fx][fy][i]);
}
}
int main(){
cin>>n>>m>>d;
for(int i=1;i<=d;i++){
scanf("%lld",&a[i]);
}
char ch;
for(int i=0;i<(1<<d);i++)//预处理出每种状态下的总价值val[i](i是状态哦)
for(int j=1;j<=d;j++)
if(i&(1<<(j-1))) val[i]+=a[j];//如果状态中存在j号豆豆
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf(" %c",&ch);
if(ch=='#') num[i][j]=-1;
else if(ch<='9'&&ch>='0'){
x[ch-'0']=i,y[ch-'0']=j,num[i][j]=ch-'0';//num[i]存储每个点的数据
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!num[i][j]) Spfa(i,j);//因为要围豆豆,当然不能从豆豆出发,障碍物也不行
cout<<ans<<endl;
return 0;
}

还有一种更简单一点的写法:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
const int maxn=11,maxm=1001;
#define ll long long
int n,m,d,cross;
int dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1};//第一位数dx[0],dy[0]是无意义的
ll f[maxn][maxn][maxm],val[maxn],vis[maxn][maxn],in[maxn][maxn][maxm],x[maxn],y[maxn];
struct node{
int started,ended,condition;//分别存储起点,终点,状态
node();
node(int x,int y,int z){
started=x,ended=y,condition=z;
}
};
queue<node> q;
ll now_condition,now_change,ans=0;
void Check(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 t=q.front();q.pop();
int u=t.started,v=t.ended,w=t.condition;
for(int k=1;k<=4;k++){
int xx=u+dx[k],yy=v+dy[k];
if(xx<=0||yy<=0||xx>n||yy>m||vis[xx][yy]!=0) continue;
now_condition=w;
now_change=f[u][v][w]-1;
if(k<=2){
cross=min(xx,u);
for(int i=1;i<=d;i++){
if(x[i]!=cross||y[i]>yy) continue;
if(now_condition>>(i-1)&1){
now_change-=val[i];
//cout<<now_condition<<endl;
}
else now_change+=val[i];
now_condition=now_condition^(1<<(i-1));
}
}
if(!in[xx][yy][now_condition]++) f[xx][yy][now_condition]=now_change,q.push(node(xx,yy,now_condition));
}
}
for(int i=0;i<(1<<d);i++){
if(in[fx][fy][i]) ans=max(ans,f[fx][fy][i]);
}
}
int main(){
cin>>n>>m>>d;
for(int i=1;i<=d;i++){
scanf("%lld",&val[i]);
}
char ch;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf(" %c",&ch);
if(ch=='#') vis[i][j]=-1;
else if(ch<='9'&&ch>='0'){
x[ch-'0']=i,y[ch-'0']=j,vis[i][j]=ch-'0';
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!vis[i][j]) Check(i,j);
cout<<ans<<endl;
return 0;
}

洛谷P2566 [SCOI2009]围豆豆(状压dp+spfa)的更多相关文章

  1. 洛谷P2761 软件补丁问题(状压DP,SPFA)

    题意 描述不清... Sol 网络流24题里面怎么会有状压dp?? 真是狗血,不过还是简单吧. 直接用$f[sta]$表示当前状态为$sta$时的最小花费 转移的时候枚举一下哪一个补丁可以搞这个状态 ...

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

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

  3. 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)

    洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...

  4. 洛谷 P1278 单词游戏 【状压dp】

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  5. 洛谷P2761 软件补丁问题 [状压DP,SPFA]

    题目传送门 软件补丁问题 题目描述 T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程序.每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又 ...

  6. 洛谷P2704 [NOI2001]炮兵阵地 [状压DP]

    题目传送门 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图 ...

  7. 洛谷P2831 愤怒的小鸟——贪心?状压DP

    题目:https://www.luogu.org/problemnew/show/P2831 一开始想 n^3 贪心来着: 先按 x 排个序,那么第一个不就一定要打了么? 在枚举后面某一个,和它形成一 ...

  8. 洛谷P2051 [AHOI2009] 中国象棋(状压dp)

    题目简介 n*m的棋盘,对每行放炮,要求每行每列炮数<=2,求方案数%9999973 N,M<=100 题目分析 算法考虑 考虑到N,M范围较小,每一行状态只与前面的行状态有关,考虑状压D ...

  9. 洛谷$P$3160 局部极小值 $[CQOI2012]$ 状压$dp$

    正解:状压$dp$ 解题报告: 传送门! 什么神仙题昂,,,反正我是没有想到$dp$的呢$kk$,,,还是太菜了$QAQ$ 首先看数据范围,一个4×7的方格,不难想到最多有8个局部极小值,过于显然懒得 ...

随机推荐

  1. Mac 制作 Linux 启动盘

    本文原始地址:https://sitoi.cn/posts/28583.html 前期准备 一个 Mac 电脑 一个 U 盘(8GB 以上) 下载好 Linux 系统镜像(iso 文件) 具体步骤 挂 ...

  2. 什么?你还不会获取地址栏(url)的值

    function getUrlParam(name) {//封装方法 var reg = new RegExp("(^|&)" + name + "=([^&am ...

  3. Mysql索引扫盲总结

    本文总结了一些MySQL索引的基本概念和原理,如果可以快速清晰回答这些问题可以出门左转提提宝贵建议. 什么是索引?索引为什么查询快,索引的数据结构是什么? 聚簇索引/非聚簇索引区别? 什么是覆盖索引? ...

  4. OC语言

    // // main.m // 测试题05 // // Created by yang sanchao on 9/12/15. // Copyright (c) 2015 yang sanchao. ...

  5. 嵌入式Linux内核开发工程师必须掌握的三十道题

    如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师. 1. Linux中主要有哪几种内核锁?(进程同步与互斥) (1)自旋锁:非睡眠锁 (2)信号量: ...

  6. zabbix服务无法正常启动

    环境介绍 操作系统 centos 7.4 zabbix 3.4.7   故障现象说明 zabbix agent无法启动   web 监控不到客户端服务器   查看日志报错 提示不能打开日志,不能创建信 ...

  7. 探究:Adobe Premiere Pro CC 2018 导入SRT字幕显示不全问题

    问题:如果使用PR,大概率会遇到导入SRT格式的字幕文件后,PR里面显示的字幕不完整,字幕丢失的问题. 探究:字幕文件的内容正常,导入PR后字幕出现丢失. 查看字幕文件,并测试,发现如下图,如果出现字 ...

  8. postman切换环境

    原文链接:https://www.cnblogs.com/nicole-zhang/p/11498384.html 通常会有多个测试环境,针对同一个接口来说,可能只是域名有变化,此时可以添加postm ...

  9. Zookeeper——基本使用以及应用场景(手写实现分布式锁和rpc框架)

    文章目录 Zookeeper的基本使用 Zookeeper单机部署 Zookeeper集群搭建 JavaAPI的使用 Zookeeper的应用场景 分布式锁的实现 独享锁 可重入锁 实现RPC框架 基 ...

  10. 从字符串到常量池,一文看懂String类设计

    从一道面试题开始 看到这个标题,你肯定以为我又要讲这道面试题了 // 这行代码创建了几个对象? String s3 = new String("1"); 是的,没错,我确实要从这里 ...