数据范围很小考虑状压DP
首先一个重要的性质:判断一个多边形包围住了一个点的方法为:从该点任意向外引出一条射线,如果与当前多边形的边相交奇数次则包住了这个点,否则没有包住这个点。
我们可以让每一个重要点水平向右引出直线并计算当前围成的多边形与它们相交次数的奇偶性来判断当前多边形包到了几个重要点。
设\(f_{i,j,k}\)表示当前多边形在点\((i,j)\),每一个重要点向右引出的射线与当前多边形相交次数奇偶性为\(k\)时的最小步数,转移枚举四边。
注意\(k\)中最好计算把所有重要点向下平移\(0.5\)个单位长度后向右引出的射线与当前多边形的相交次数,否则可能在计算是出现算重、算漏的情况。
不难发现转移是一个最短路的形式,于是BFS求一下最短路即可。
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
//This code is written by Itst
using namespace std;
const int dir[4][2] = {0,1,0,-1,1,0,-1,0};
char Map[23][23];
int val[9] , add[23][23] , dp[23][23][1 << 9] , sum[2007];
int N , M , D , logg2[2007];
bool vis[23][23][1 << 9];
struct zt{
int x , y , cir;
};
queue < zt > q;
void bfs(int i , int j){
memset(dp , 0x3f , sizeof(dp));
dp[i][j][0] = 0;
vis[i][j][0] = 1;
q.push((zt){i , j , 0});
while(!q.empty()){
zt t = q.front();
q.pop();
vis[t.x][t.y][t.cir] = 0;
for(int i = 0 ; i < 4 ; ++i){
int p = t.x + dir[i][0] , s = t.y + dir[i][1] , r = t.cir;
if(i == 2) r ^= add[p][s];
if(i == 3) r ^= add[p + 1][s];
if(Map[p][s] == '0' && dp[p][s][r] > dp[t.x][t.y][t.cir] + 1){
dp[p][s][r] = dp[t.x][t.y][t.cir] + 1;
if(!vis[p][s][r]){
vis[p][s][r] = 1;
q.push((zt){p , s , r});
}
}
}
}
}
int main(){
cin >> N >> M >> D;
for(int i = 0 ; i < D ; ++i)
cin >> val[i];
for(int i = 2 ; i < 1 << D ; ++i) logg2[i] = logg2[i >> 1] + 1;
for(int i = 1 ; i < 1 << D ; ++i)
sum[i] = sum[i - (1 << logg2[i])] + val[logg2[i]];
for(int i = 1 ; i <= N ; ++i)
for(int j = 1 ; j <= M ; ++j){
cin >> Map[i][j];
if(Map[i][j] >= '1' && Map[i][j] <= '9')
for(int k = j + 1 ; k <= M ; ++k)
add[i][k] += 1 << (Map[i][j] - '1');
}
int ans = 0;
for(int i = 1 ; i <= N ; ++i)
for(int j = 1 ; j <= M ; ++j){
bfs(i , j);
for(int k = 1 ; k < 1 << D ; ++k)
ans = max(ans , sum[k] - dp[i][j][k]);
}
cout << ans;
return 0;
}
//CF375C
#include<iostream>
#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
//This code is written by Itst
using namespace std;
const int dir[4][2] = {0,1,0,-1,1,0,-1,0};
char Map[23][23];
int val[9] , add[23][23] , dp[23][23][1 << 9] , sum[2007];
int N , M , D , X , Y , logg2[2007];
bool vis[23][23][1 << 9];
struct zt{
int x , y , cir;
};
queue < zt > q;
void bfs(int i , int j){
memset(dp , 0x3f , sizeof(dp));
dp[i][j][0] = 0;
vis[i][j][0] = 1;
q.push((zt){i , j , 0});
while(!q.empty()){
zt t = q.front();
q.pop();
vis[t.x][t.y][t.cir] = 0;
for(int i = 0 ; i < 4 ; ++i){
int p = t.x + dir[i][0] , s = t.y + dir[i][1] , r = t.cir;
if(i == 2) r ^= add[p][s];
if(i == 3) r ^= add[p + 1][s];
if((Map[p][s] == '.' || Map[p][s] == 'S') && dp[p][s][r] > dp[t.x][t.y][t.cir] + 1){
dp[p][s][r] = dp[t.x][t.y][t.cir] + 1;
if(!vis[p][s][r]){
vis[p][s][r] = 1;
q.push((zt){p , s , r});
}
}
}
}
}
int main(){
cin >> N >> M;
for(int i = 1 ; i <= N ; ++i)
for(int j = 1 ; j <= M ; ++j){
cin >> Map[i][j];
if(Map[i][j] >= '1' && Map[i][j] <= '9'){
++D;
for(int k = j + 1 ; k <= M ; ++k)
add[i][k] += 1 << (Map[i][j] - '1');
}
else if(Map[i][j] == 'S'){X = i; Y = j;}
}
for(int i = 0 ; i < D ; ++i) cin >> val[i];
for(int i = 2 ; i < 1 << D ; ++i) logg2[i] = logg2[i >> 1] + 1;
for(int i = 1 ; i < 1 << D ; ++i)
sum[i] = sum[i - (1 << logg2[i])] + val[logg2[i]];
int ans = 0 , cnt = D;
for(int i = 1 ; i <= N ; ++i)
for(int j = 1 ; j <= M ; ++j)
if(Map[i][j] == 'B'){
for(int k = j + 1 ; k <= M ; ++k)
add[i][k] += 1 << cnt;
cnt++;
}
bfs(X , Y);
for(int k = 1 ; k < 1 << D ; ++k)
ans = max(ans , sum[k] - dp[X][Y][k]);
cout << ans;
return 0;
}