洛谷題面:https://www.luogu.org/problemnew/show/P2566
由每一個豆子引一條射線,與射線交點個數爲奇數至關於多邊形圍住了它,這樣能夠定義一個狀態f[x][y][s]表示從起點出發,走到(x,y)處時的路徑與D顆豆子引出的射線相交的奇偶性狀態爲s,最少需多少步。而後跑最短路轉移便可。
然而,有一個小問題就是轉移時如何判與豆子引出的射線相交。若是單純按與線相交的拐點來計算的話,咱們發現會有這兩種大相徑庭的狀況被算成了同樣。
理論上藍色路徑應該是0,綠色路徑應該是1纔對。
因而咱們能夠選擇統計時把邊定一下向,像綠色路徑這種穿出的狀況就不重複計算了。詳見代碼。c++
#include<bits/stdc++.h> using namespace std; const int N = 15; #define min(a,b) ((a)<(b)?(a):(b)) #define rep(i,a,b) for(register int i=(a);i<=(b);++i) int n,m,w[N],val[1<<10],D; char mp[N][N]; int dis[N][N][1<<10],ans; struct la{int x,y,s;}bean[N]; queue<la> q; bool vis[N][N][1<<10]; int rx[4]={0,1,0,-1}; int ry[4]={1,0,-1,0}; inline bool isin(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;} inline void spfa(int x,int y){ memset(dis,0x3f,sizeof(dis)); q.push((la){x,y,0});dis[x][y][0]=0;vis[x][y][0]=1; while(!q.empty()){ la u=q.front();q.pop();vis[u.x][u.y][u.s]=0; rep(i,0,3){ int nx=u.x+rx[i],ny=u.y+ry[i],ns=u.s; if(!isin(nx,ny)||mp[nx][ny]!='0')continue; rep(j,0,D-1){ if(ny>bean[j].y&&((nx==bean[j].x&&u.x>bean[j].x)||(nx>bean[j].x&&u.x==bean[j].x)))ns^=(1<<j); } if(dis[nx][ny][ns]>dis[u.x][u.y][u.s]+1){ dis[nx][ny][ns]=dis[u.x][u.y][u.s]+1; if(vis[nx][ny][ns])continue; vis[nx][ny][ns]=1; q.push((la){nx,ny,ns}); } } } } int main(){ scanf("%d%d",&n,&m); scanf("%d",&D); rep(i,0,D-1){ scanf("%d",&w[i]); } rep(j,0,(1<<D)-1){ rep(i,0,D-1){ if(j&(1<<i))val[j]+=w[i]; } } rep(i,1,n){ scanf("%s",mp[i]+1); rep(j,1,m){ if(mp[i][j]>'0')bean[mp[i][j]-'0'-1]=(la){i,j,0}; } } rep(i,1,n){ rep(j,1,m){ if(mp[i][j]!='0')continue; spfa(i,j); rep(k,0,(1<<D)-1)ans=max(ans,val[k]-dis[i][j][k]); } } printf("%d\n",ans); return 0; }