题解
题目已经告诉了如何判断一个点是否在一个多边形里面,
而关于自交的问题,就将它当作没有自交就好了。
看到数据范围,特殊点只有很少,考虑如何设状态,
用fx,y,sfx,y,s表示当前走的点(x,y),特殊格子上面经过的线的奇偶性的2进制状态,
有了这个状态就可以bfs了。
code
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 2560
#define M 103
#define db double
#define P putchar
#define G getchar
using namespace std;
char ch;
int f[23][23][1030],n,m,x,y,xx,yy,t,v,ss,sx,sy,tr;
int z[13],fx[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
int head,tail,q[3][N*8],ans,p[2][13],cnt,w[13];
bool bz[23][23][1030];
char s[23][23];
int get(int x,int y,int s)
{
for(int i=1;i<=cnt;i++)
if(p[1][i]==y && p[0][i]>x)s^=z[i-1];
return s;
}
void dfs(int ss,int x,int y)
{
ans=max(ans,y-f[sx][sy][ss]);
if(x>cnt)return;
if('1'<=s[p[0][x]][p[1][x]] && s[p[0][x]][p[1][x]]<='8')
dfs(ss|z[x-1],x+1,y+w[s[p[0][x]][p[1][x]]-'0']);
dfs(ss,x+1,y);
}
int main()
{
z[0]=1;
for(int i=1;i<12;i++)
z[i]=z[i-1]<<1;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(ch=G();!(ch=='#' || ch=='S' || ch=='.' || ch=='B' || ('1'<=ch && ch<='8'));ch=G());
for(m=0;ch=='#' || ch=='S' || ch=='.' || ch=='B' || ('1'<=ch && ch<='8');ch=G())
{
s[i][++m]=ch;
if(ch=='B' || ('1'<=ch && ch<='8'))
{
cnt++,p[0][cnt]=i,p[1][cnt]=m;
if('1'<=ch && ch<='8')tr++;
}
if(ch=='S')sx=i,sy=m,s[i][m]='.';
}
}
for(int i=1;i<=tr;i++)
scanf("%d\n",&w[i]);
memset(f,127,sizeof(f));
memset(bz,1,sizeof(bz));
q[0][1]=sx;q[1][1]=sy;q[2][1]=0;//get(sx,sy,0);
f[sx][sy][q[2][1]]=0;bz[sx][sy][q[2][1]]=0;
for(head=0,tail=1;head<tail;)
{
head++;
x=q[0][head];
y=q[1][head];
t=q[2][head];
v=f[x][y][t];
for(int k=0;k<4;k++)
{
xx=x+fx[k][0];
yy=y+fx[k][1];
ss=t;
if(xx<1 || yy<1 || xx>n || yy>m)continue;
if(s[xx][yy]!='.')continue;
if(k==1)ss=get(x,yy,ss);
if(k==3)ss=get(x,y,ss);
if(f[xx][yy][ss]>v+1)
{
f[xx][yy][ss]=v+1;
if(bz[xx][yy][ss])
{
bz[xx][yy][ss]=0;
tail++;
q[0][tail]=xx;
q[1][tail]=yy;
q[2][tail]=ss;
}
}
}
bz[x][y][t]=1;
}
ans=-2147483647;
dfs(0,1,0);
printf("%d\n",ans);
return 0;
}