卡常卡了好久qwq
可以先用记忆化搜索搜出每个位置往四个方向走会走到哪,注意判走到已经走过的地方避免死循环
f[l][r][i][j]表示在(i,j)合成机器人l~r的最小花费
有
f[l][r][i][j]=minf[l][r][di][dj]+1(di,dj)−>(i,j)
f[l][r][i][j]=min(f[l][k][i][j]+f[k+1][j][i][j])
对于第二个转移,我们按长度从小到大dp,处理到f[l,r,i,j]时枚举k就行了
对于第一个转移,本来要用spfa,因为转移的边权都相同,可以bfs
维护两个队列,把初始状态放在第一个队列,拓展出来的状态放进第二个队列,每次取出两个队列的队头比较,用小的去拓展
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;
const int maxn = 505;
const int maxk = 10;
const int maxd = 4;
const int dx[] = {-1,0,1,0};
const int dy[] = {0,1,0,-1};
int n,m,K;
// 11 +1 12 -1
int a[maxn][maxn];
struct point{int x,y;}d[maxn][maxn][maxd],nul;
bool v[maxn][maxn][maxd];
bool cmp(const int &x,const int &y)
{
if(!x||!y||x>n||y>m||a[x][y]==-1) return false;
return true;
}
point search(const int x,const int y,int k)
{
if(v[x][y][k]) return nul;
if(d[x][y][k].x) return d[x][y][k];
int tk=k;
v[x][y][tk]=true;
if(a[x][y]==11) k=(k+1)%maxd;
if(a[x][y]==12) k=(k+3)%maxd;
int nx=x+dx[k],ny=y+dy[k];
if(!cmp(nx,ny)) d[x][y][tk]=(point){x,y};
else d[x][y][tk]=search(nx,ny,k);
v[x][y][tk]=false;
return d[x][y][tk];
}
struct node{int x,y,d;}t[maxn*maxn]; int tp;
queue<node>q1,q2; int h1,h2;
inline bool cmpt(const node x,const node y){return x.d<y.d;}
int f[maxk][maxk][maxn][maxn];
char str[maxn];
int main()
{
nul.x=nul.y=-1;
scanf("%d%d%d",&K,&m,&n);
for(int i=1;i<=n;i++)
{
scanf("%s",str);
for(int j=1;j<=m;j++)
{
char cc=str[j-1];
if(cc=='x') a[i][j]=-1;
else if(cc=='.') a[i][j]=0;
else if(cc=='A') a[i][j]=12;
else if(cc=='C') a[i][j]=11;
else a[i][j]=cc-'0';
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=0;k<maxd;k++) d[i][j][k].x=d[i][j][k].y=0;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
{
for(int k=0;k<maxd;k++) if(d[i][j][k].x==0)
d[i][j][k]=search(i,j,k);
}
for(int l=1;l<=K;l++) for(int r=1;r<=K;r++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) f[l][r][i][j]=-1;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]>0&&a[i][j]<10)
f[a[i][j]][a[i][j]][i][j]=0;
for(int L=1;L<=K;L++)
{
for(int l=1;l+L-1<=K;l++)
{
int r=l+L-1;
tp=0;
for(int k=l;k<r;k++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]!=-1)
{
int &tmp=f[l][r][i][j];
if(f[l][k][i][j]!=-1&&f[k+1][r][i][j]!=-1)
{
int temp=f[l][k][i][j]+f[k+1][r][i][j];
if(tmp==-1||tmp>temp) tmp=temp;
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(f[l][r][i][j]!=-1)
t[++tp]=(node){i,j,f[l][r][i][j]};
sort(t+1,t+tp+1,cmpt);
for(int i=1;i<=tp;i++) q1.push(t[i]);
h1=h2=inf;
if(!q1.empty()) h1=(q1.front()).d;
while(h1!=inf||h2!=inf)
{
if(h1<=h2)
{
node now=q1.front(); q1.pop();
int x=now.x,y=now.y;
if(f[l][r][x][y]==h1)
{
for(int k=0;k<maxd;k++) if(d[x][y][k].x!=-1)
{
int nx=d[x][y][k].x,ny=d[x][y][k].y,&kk=f[l][r][nx][ny];
if(kk==-1||kk>h1+1)
{
kk=h1+1;
q2.push((node){nx,ny,kk});
}
}
}
}
else
{
node now=q2.front(); q2.pop();
int x=now.x,y=now.y;
if(f[l][r][x][y]==h2)
{
for(int k=0;k<maxd;k++) if(d[x][y][k].x!=-1)
{
int nx=d[x][y][k].x,ny=d[x][y][k].y,&kk=f[l][r][nx][ny];
if(kk==-1||kk>h2+1)
{
kk=h2+1;
q2.push((node){nx,ny,kk});
}
}
}
}
h1=h2=inf;
if(!q1.empty()) h1=(q1.front()).d;
if(!q2.empty()) h2=(q2.front()).d;
}
}
}
int re=-1;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(f[1][K][i][j]!=-1)
if(re>f[1][K][i][j]||re==-1) re=f[1][K][i][j];
printf("%d\n",re);
return 0;
}