Link
首先看到这个题先想状压吧,但是我因为 sb T2 调的时间太长了并没有仔细想这个东西,发现并不是那么难?
首先看到宝藏和陷阱的和是小于 8 的,直接想状压。而且数据范围又极小,所以我们可以直接设 dp[i][j][s] 表示在 (i,j) 这个点,所包括的宝藏的状态是 S 的最小步数。
状态并不是很难想,但是问题是如何满足题目里所要求的条件。首先,对于一些陷阱,我们可以直接把它看成宝藏,只不过他的价值是负的极大值,所以我们选的时候最优的情况一定不会包括陷阱。那么就剩下了一个问题,如何判断是否在所走的这个多边形里面。
我们对于每一个宝藏只考虑从这个点竖着发出的射线,这样的话,只有走横向边的时候才会奇偶性发生改变。走竖向边的时候不用管,这样的话我们把这个线段看成是左开右闭的,然后直接判断即可。利用 bfs
进行转移。
#include<bits/stdc++.h>
#define g() getchar()
#define il inline
#define ull unsigned long long
#define eps 1e-10
#define ll long long
#define pa pair<int, int>
#define for_1(i, n) for(int i = 1; i <= (n); ++i)
#define for_0(i, n) for(int i = 0; i < (n); ++i)
#define for_xy(i, x, y) for(int i = (x); i <= (y); ++i)
#define for_yx(i, y, x) for(int i = (y); i >= (x); --i)
#define for_edge(i, x) for(int i = head[x]; i; i = nxt[i])
#define int long long
#define DB double
#define ls (p<<1)
#define rs (p<<1|1)
#define m_p make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 10, INF = 150000, mod = 1e9 + 7;
il int qpow(int x, int k) {int ans = 1; while(k) {if(k & 1) ans = ans * x % mod; x = x * x % mod; k >>= 1; } return ans; }
inline int re() {
int x = 0, p = 1;
char ch = getchar();
while(ch > '9' || ch < '0') {if(ch == '-') p = -1; ch = getchar();}
while(ch <= '9' and ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * p;
}
int n, m, sx, sy, tot;
char S[30][30];
int a[30], b[30], val[30], sum[300], dp[30][30][300];
int dx[5] = {0, 0, 0, 1, -1}, dy[5] = {0, 1, -1, 0, 0};
struct Node{ int x, y, s; };
queue<Node> q;
il bool In(int nowx, int nowy, int nx, int ny, int id) {
if(nx == a[id] and ny < b[id]) if(nowx < nx) return 1;
if(nowx == a[id] and nowy < b[id]) if(nowx > nx) return 1;
return 0;
}
il int bfs() {
while (q.size()) q.pop(); memset(dp, -1, sizeof(dp)); q.push(Node{sx, sy, 0});
dp[sx][sy][0] = 0; int ans = 0;
while(q.size()) {
int x = q.front().x, y = q.front().y, s = q.front().s; q.pop();
if(x == sx and y == sy) {ans = max(ans, sum[s] - dp[x][y][s]);}
for(int i = 1; i <= 4; ++i) {
int nx = x + dx[i], ny = y + dy[i]; if(nx <= 0 || nx > n || ny <= 0 || ny > m || (S[nx][ny] != '.' and S[nx][ny] != 'S') ) continue;
int ns = s; for(int j = 1; j <= tot; ++j) if(In(x, y, nx, ny, j)) ns ^= (1 << (j - 1));
if(dp[nx][ny][ns] == -1) {dp[nx][ny][ns] = dp[x][y][s] + 1; q.push(Node{nx, ny, ns}); }
}
}
return ans;
}
signed main() {
n = re(), m = re(); for_1(i, n) scanf("%s", S[i] + 1);
for_1(i, n) {
for_1(j, m) {
char ch = S[i][j];
if(ch == 'S') sx = i, sy = j;
else if(ch != '.' and ch != 'B' and ch != '#') {a[ch - 48] = i, b[ch - 48] = j; ++tot; }
}
}
for_1(i, tot) val[i] = re();
for_1(i, n) for_1(j, m) {if(S[i][j] == 'B') {a[++tot] = i, b[tot] = j, val[tot] = -INF; }}
for(int st = 1; st < (1<<tot); ++st) {for_1(i, tot) if((st>>(i-1))&1) sum[st] += val[i];}
int ans = bfs(); printf("%lld\n", ans);
}
__EOF__
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析