http://blog.csdn.net/qq574857122/article/details/17797639?locationNum=2&fps=1
状压+最短路
判断一个点在不在路径内,选择一个方向数边的条数,判断奇偶性就好了
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,n) for (int i=0;i<n;++i)
const int u[]={1,0,-1,0},v[]={0,1,0,-1};
int n,m,sx,sy,ans,T,B,p[1<<8],price[9],c[22][22],d[22][22][1<<8],f[200000],g[200000],e[200000];
char s[22][22];
int main()
{
scanf("%d%d",&n,&m);
rep(i,n){
scanf("%s",s[i]);
rep(j,m) if (s[i][j]=='S') sx=i,sy=j,s[i][j]='.';
rep(j,m) if (s[i][j]>'0' && s[i][j]<'9'){++T; rep(k,i) c[k][j]|=1<<(s[i][j]-49);}
}
rep(i,T) scanf("%d",price+i); B=T;
rep(i,1<<T) rep(j,T) if (i>>j&1) p[i]+=price[j];
rep(i,n) rep(j,m) if (s[i][j]=='B'){rep(k,i) c[k][j]|=1<<B; ++B;}
int h=0,t=1; f[1]=sx,g[1]=sy,e[1]=0; memset(d,6,sizeof(d)); d[sx][sy][0]=0;
while (h<t){
int x=f[++h],y=g[h],z=e[h],D=d[x][y][z];
rep(dir,4){
int i=x+u[dir],j=y+v[dir],k=z;
if (i<0 || i>=n || j<0 || j>=m || s[i][j]!='.') continue;
if (y!=j) k^=c[i][min(y,j)];
if (D+1<d[i][j][k]) d[i][j][k]=D+1,f[++t]=i,g[t]=j,e[t]=k;
}
}
rep(i,1<<T) ans=max(ans,p[i]-d[sx][sy][i]);
printf("%d\n",ans);
return 0;
}