题面传送门

注意到这题中宝藏 \(+\) 炸弹个数最多只有 \(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. VS2019中安装2017,2015

    VS2019中安装2017,2015

  2. Java:容器类线程不安全

    Java:容器类线程不安全 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 1. Collection 线程不安全的举例 前言 1.当我们执行下面语句的时候,底层 ...

  3. 看动画学算法之:队列queue

    目录 简介 队列的实现 队列的数组实现 队列的动态数组实现 队列的链表实现 队列的时间复杂度 简介 队列Queue是一个非常常见的数据结构,所谓队列就是先进先出的序列结构. 想象一下我们日常的排队买票 ...

  4. Beta阶段性总结

    1.题士开发总结 2.反思 2.1 Issue管理 从0522敲定各个功能的API后,团队成员及时沟通,积极开发,但由于开发过程没能有效体现在issue上(如未能及时在issue上形成记录,功能开发完 ...

  5. AIApe问答机器人Scrum Meeting 5.1

    Scrum Meeting 5 日期:2021年5月1日 会议主要内容概述:汇报两日工作. 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 李明昕 后端 Task ...

  6. 2021.8.3考试总结[NOIP模拟29]

    T1 最长不下降子序列 数据范围$1e18$很不妙,但模数$d$只有$150$,考虑从这里突破. 计算的式子是个二次函数,结果只与上一个值有关,而模$d$情况下值最多只有$150$个,就证明序列会出现 ...

  7. Java并发:ReadWriteLock 读写锁

    读写锁在同一时刻可以允许多个线程访问,但是在写线程访问,所有的读线程和其他写线程均被阻塞. 读写锁不像 ReentrantLock 那些排它锁只允许在同一时刻只允许一个线程进行访问,读写锁可以允许多个 ...

  8. python 3 range函数类型

    在python3中 print(range(10))range(0,10) 得出的结果是 range(0,10) ,而不是[0,1,2,3,4,5,6,7,8,9] ,为什么呢?而且原来Python2 ...

  9. linux shell 函数返回值问题(超过255)

    最近再写一个shell测试的时候出现问题,函数返回值异常 用shell计算斐波那契数列数列,写了一个shell函数,然后调用的,验证的时候我只随便计算了几个数(10以内),确认结果是正确的就提交了,后 ...

  10. 【java设计模式】(10)---模版方法模式(案例解析)

    一.概念 1.概念 模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式. 它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的 ...