题面传送门

注意到这题中宝藏 \(+\) 炸弹个数最多只有 \(8\) 个,故考虑状压,设 \(dp[x][y][S]\) 表示当前坐标为 \((x,y)\),有且仅有 \(S\) 当中的物品被包围在凸多边形内部所走过的最少步数。

考虑转移,枚举与 \((x,y)\) 相邻的点 \((x',y')\)。但是 \(S\) 的变化可能有些棘手。这里有一个结论,对于某一点 \((x,y)\),任意引出一条射线,如果它与多边形有奇数个交点,那么 \((x,y)\) 就在多边形内部。由于这里引出的射线可以沿任何方向,那么我们不妨统一假设射线的方向都是向右,故这里的状态 \(S\) 就可以理解为:满足 \((x,y)\) 向右引出的射线与多边形交点个数为奇数的点的集合。

这样一来状态是倒搞明白了,但是直接这样转移还是可能会出现一些问题,因为有可能我们是从某个点 \((x,y)\) 向右走到 \((x,y+1)\),而对于某个横坐标也为 \(x\) 的点 \((x,y')\),它向右引出的射线与多边形出现了重合的情况,进而就不好计算交点个数。不过这个问题很容易解决,因为行走的路径不会经过宝藏/炸弹,故横向的线段并不会影响交点个数,于是只需计算纵向的线段就行了。

但是这样还是会出现问题。比方说下图,对于点 \(A\) 向右引出的橙色射线,如果按照我们的判断其与多边形有两个交点 \(B,C\),但如果我们把横向的线段去掉,将两个纵向线段拼在一起,就会发现有用的交点只有 \(1\) 个。这个问题也异常容易解决,考虑将每条纵向的线段看作一个上开下闭的线段,当从 \((x,y)\) 走到 \((x+1,y)\) 时只改变满足 \(x'=x+1,y'<y\) 的点 \((x',y')\) 的状态;当从 \((x,y)\) 走到 \((x-1,y)\) 时只改变满足 \(x'=x,y'<y\) 的点 \((x',y')\) 的状态。这样一来就可以避免这个问题了。

最短路转移即可。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc((x%10)+'0');}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=20;
const int MAXP=256;
const int MAXM=8;
const int INF=0x3f3f3f3f;
const int dx[]={1,0,-1,0};
const int dy[]={0,1,0,-1};
int n,m,sx,sy;char s[MAXN+3][MAXN+3];
int dp[MAXN+2][MAXN+2][MAXP+3];
int px[MAXM+2],py[MAXM+2],a[MAXM+2],c1=0,c2=0;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(s[i][j]=='S') sx=i,sy=j;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(isdigit(s[i][j])){
px[s[i][j]^48]=i;py[s[i][j]^48]=j;c1++;
} c2=c1;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(s[i][j]=='B') px[++c2]=i,py[c2]=j;
for(int i=1;i<=c1;i++) scanf("%d",&a[i]);
memset(dp,63,sizeof(dp));dp[sx][sy][0]=0;
queue<pair<pii,int> > q;q.push(mp(mp(sx,sy),0));
while(!q.empty()){
pair<pii,int> p=q.front();q.pop();
int x=p.fi.fi,y=p.fi.se,msk=p.se;
// printf("%d %d %d %d\n",x,y,msk,dp[x][y][msk]);
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||nx>n||ny<1||ny>m) continue;
if(s[nx][ny]!='.'&&s[nx][ny]!='S') continue;
int nmsk=msk;
for(int j=1;j<=c2;j++) if((!(px[j]^x)&&!(i^2)||!(px[j]^nx)&&!i)&&py[j]<ny)
nmsk^=1<<j-1;
if(dp[nx][ny][nmsk]==INF){
dp[nx][ny][nmsk]=dp[x][y][msk]+1;
q.push(mp(mp(nx,ny),nmsk));
}
}
}
int ans=-INF;
for(int i=0;i<(1<<c1);i++) if(dp[sx][sy][i]!=INF){
int sum=0;
for(int j=0;j<c1;j++) sum+=a[j+1]*(i>>j&1);
chkmax(ans,sum-dp[sx][sy][i]);
} printf("%d\n",ans);
return 0;
}

Codeforces 375C - Circling Round Treasures(状压 dp+最短路转移)的更多相关文章

  1. Codeforces 375C Circling Round Treasures - 最短路 - 射线法 - 位运算

    You have a map as a rectangle table. Each cell of the table is either an obstacle, or a treasure wit ...

  2. 旅游(CSUST省赛选拔赛2+状压dp+最短路)

    题目链接:http://csustacm.com:4803/problem/1016 题目: 思路:状压dp+最短路,比赛的时候有想到状压dp,但是最短路部分写挫了,然后就卡死了,对不起出题人~dis ...

  3. CF 375C Circling Round Treasures [DP(spfa) 状压 射线法]

    C - Circling Round Treasures 题意: 在一个$n*m$的地图上,有一些障碍,还有a个宝箱和b个炸弹.你从(sx,sy)出发,走四连通的格子.你需要走一条闭合的路径,可以自交 ...

  4. Codeforces 453B Little Pony and Harmony Chest:状压dp【记录转移路径】

    题目链接:http://codeforces.com/problemset/problem/453/B 题意: 给你一个长度为n的数列a,让你构造一个长度为n的数列b. 在保证b中任意两数gcd都为1 ...

  5. codeforces 8C. Looking for Order 状压dp

    题目链接 给n个物品的坐标, 和一个包裹的位置, 包裹不能移动. 每次最多可以拿两个物品, 然后将它们放到包里, 求将所有物品放到包里所需走的最小路程. 直接状压dp就好了. #include < ...

  6. Codeforces 429C Guess the Tree(状压DP+贪心)

    吐槽:这道题真心坑...做了一整天,我太蒻了... 题意 构造一棵 $ n $ 个节点的树,要求满足以下条件: 每个非叶子节点至少包含2个儿子: 以节点 $ i $ 为根的子树中必须包含 $ c_i ...

  7. Codeforces 895C Square Subsets(状压DP 或 异或线性基)

    题目链接  Square Subsets 这是白书原题啊 先考虑状压DP的做法 $2$到$70$总共$19$个质数,所以考虑状态压缩. 因为数据范围是$70$,那么我们统计出$2$到$70$的每个数的 ...

  8. 【题解】codeforces 8c Looking for Order 状压dp

    题目描述 Lena喜欢秩序井然的生活.一天,她要去上大学了.突然,她发现整个房间乱糟糟的--她的手提包里的物品都散落在了地上.她想把所有的物品都放回她的手提包.但是,这里有一点问题:她一次最多只能拿两 ...

  9. Codeforces 895C Square Subsets:状压dp【组合数结论】

    题目链接:http://codeforces.com/problemset/problem/895/C 题意: 给你n个数a[i].(n <= 10^5, 1 <= a[i] <= ...

随机推荐

  1. HCIP-RSTP

    端口角色 根端口(RP): 非根桥收到最优的BPDU配置信息的端口为根端口,(到根桥开销最小的端口),根桥没有根端口. 指定端口(DP): 两非根交换机之间连接的两个端口必有一个为指定端口,比较两个非 ...

  2. UltraSoft - Beta - Scrum Meeting 9

    Date: May 25th, 2020. Scrum 情况汇报 进度情况 组员 负责 今日进度 q2l PM.后端 记录Scrum Meeting Liuzh 前端 用户忘记密码界面初稿完成 Kkk ...

  3. python的random模块生成随机数

    python的random函数 random.random() 生成0-1之间的随机数 random.uniform(a,b)生成a,b之间的浮点数 random.randint(a,b)生成a,b之 ...

  4. Linux内核漏洞精准检测如何做?SCA工具不能只在软件层面

    摘要:二进制SCA工具要想更好的辅助安全人员实现安全审计.降低漏洞检测的误报率,必须向更细颗粒度的检测维度发展,而不仅仅停留在开源软件的层面,同时对漏洞库的要求也需要向细颗粒度的精准信息提出的挑战. ...

  5. 你一定不知道的Unsafe用法

    Unsafe是什么 首先我们说Unsafe类位于rt.jar里面sun.misc包下面,Unsafe翻译过来是不安全的,这倒不是说这个类是不安全的,而是说开发人员使用Unsafe是不安全的,也就是不推 ...

  6. 0x04

    二分: while(l<r) { int mid=(l+r)/2; if(符合条件) r=mid; else l=mid+1; } 固定下二分的写法: 终止条件:l==r: 取mid=(l+r) ...

  7. iscsi基本命令

    磁阵操作命令 根据磁阵端配置的业务地址(targetIP)和端口(3260),命令iscsiadm -m discovery -t sendtargets -p targetIP:port(3260) ...

  8. 【PowereDesigner】使用方法|mysql画图使用|不在跟新

    自己画E-R图时, 运行:Power Designer ..1 ..2 ..3 可以先放两个空的实体,然后,分别修改属性(鼠标右键,最后一项Properties),名称为:学生.课程. ..4 创建一 ...

  9. 重新整理 .net core 实践篇——— filter[四十四]

    前言 简单介绍一下filter 正文 filter 的种类,微软文档中写道: 每种筛选器类型都在筛选器管道中的不同阶段执行: 授权筛选器最先运行,用于确定是否已针对请求为用户授权. 如果请求未获授权, ...

  10. PyCharm Django Python 开发环境配置 详细教程

    PyCharm Django Python 开发环境配置 详细教程 1. Python 下载及安装 (1)根据需要的版本去 Python 官网(https://www.python.org/downl ...