CF375C Circling Round Treasures

CF375C Circling Round Treasures

题目链接:

Link

题目分析:

首先看到这个题先想状压吧,但是我因为 sb T2 调的时间太长了并没有仔细想这个东西,发现并不是那么难?

首先看到宝藏和陷阱的和是小于 8 的,直接想状压。而且数据范围又极小,所以我们可以直接设 $dp[i][j][s] $ 表示在 \((i,j)\) 这个点,所包括的宝藏的状态是 \(S\) 的最小步数。

状态并不是很难想,但是问题是如何满足题目里所要求的条件。首先,对于一些陷阱,我们可以直接把它看成宝藏,只不过他的价值是负的极大值,所以我们选的时候最优的情况一定不会包括陷阱。那么就剩下了一个问题,如何判断是否在所走的这个多边形里面。

我们对于每一个宝藏只考虑从这个点竖着发出的射线,这样的话,只有走横向边的时候才会奇偶性发生改变。走竖向边的时候不用管,这样的话我们把这个线段看成是左开右闭的,然后直接判断即可。利用 bfs 进行转移。

Code:

//editor : DRYAYST
//Wo shi ge da SHA BI
#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();
//        cout<<"x = "<<x<<" y = "<<y<<endl;
        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() {
    // freopen("land.in","r",stdin); freopen("land.out","w",stout); 
    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); 
}
/*
4 4
....
.S1.
....
....
10
*/
posted @ 2022-04-08 15:41  Zwaire  阅读(77)  评论(1)    收藏  举报