状压好题0.0
其实难点不是状压吧···应该是前面的预处理
要用到类似于spfa的bfs
RE了无数回结果发现变量名定义重了mdzz
首先说一下dp的状态定义,因为发现从i到j停下来多少次是取决于上一次撞到i的方向的
所以首先想到了dp[i][j][k]表示以k方向撞到i这个机关后已经撞过的机关为j集合的最小步数
但是我们可以发现这只和所有机关以及各个机关四周的四个格子有关
所以我们可以去掉方向维,变成dp[i][j]表示最后撞了j的撞过的是i集合的最小步数
接下来我们要考虑预处理出两个机关之间的步数
同状态定义的过程相似,我们可以只留下4*t个点
dis[i][j][k]表示从i到j,k方向的步数
最后去更新fd数组,fd[i][j]表示i到j的最小步数,这时候我们成功去掉方向维
预处理把每个机关的四周的格子当做起点做一次bfs
算机关四周的格子就是(u-1)*4+v+1,u表示机关编号,v表示方向
奉上re了好久终于AC的代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define maxn 65
#define N 105
#define inf 100000000
#define id(u,v) (u-1)*4+v+1
using namespace std;
int n,m,t,nx,ny,a[N][N],fd[maxn][maxn],dis[N][N][5],dp[1<<16][maxn];
int dir[2][4]={{0,0,-1,1},{1,-1,0,0}},bin[20],qx[200005],qy[200005];
char s[N];
bool vis[N][N];
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') {if(c=='-')f=-1;c=getchar();}
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
struct qwq {int x,y;}st[20];
void bfs(int x,int y,int id){
if(a[x][y] || x<1 || y<1 || x>n || y>m) return;
memset(dis,0x3f,sizeof dis);
qx[0]=x,qy[0]=y; vis[x][y]=1;
for(int k=0;k<4;k++) dis[x][y][k]=0;
int head=0,tail=1;//以后再也不偷懒用h和t了···
while(head!=tail){
int xx=qx[head],yy=qy[head];head++;
for(int k=0;k<4;k++){
int nowx=xx+dir[0][k],nowy=yy+dir[1][k];
if(a[nowx][nowy] || nowx<1 || nowy<1 || nowx>n || nowy>m) continue;
for(int i=0;i<4;i++)
if(dis[xx][yy][k]+(k!=i)<dis[nowx][nowy][i]){
dis[nowx][nowy][i]=dis[xx][yy][k]+(k!=i);
if(!vis[nowx][nowy]){
vis[nowx][nowy]=1;
qx[tail]=nowx,qy[tail]=nowy; tail++;
}
}
}
vis[xx][yy]=0;
}
for(int i=1;i<=t;i++)
for(int k=0;k<4;k++){
int tmp=inf,tx=st[i].x+dir[0][k],ty=st[i].y+dir[1][k];
for(int j=0;j<4;j++)
tmp=min(tmp,dis[tx][ty][j]+(tx+dir[0][j]!=st[i].x||ty+dir[1][k]!=st[i].y));
fd[id][id(i,k)]=tmp;
}
}
void DP(){
for(int i=0;i<bin[t];i++)
for(int j=1;j<=4*t+1;j++)
dp[i][j]=inf;
dp[0][4*t+1]=0;
for(int i=0;i<bin[t];i++)
for(int j=1;j<=4*t+1;j++)
if(dp[i][j]!=inf)
for(int k=1;k<=4*t;k++){
int x=i|bin[(k-1)/4];
dp[x][k]=min(dp[x][k],dp[i][j]+fd[j][k]+1);
}
int ans=inf;
for(int i=1;i<=4*t;i++)
ans=min(ans,dp[bin[t]-1][i]);
printf("%d\n",ans);
}
int main(){
n=rd(); m=rd(); t=rd();
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)
if(s[j]=='#') a[i][j]=-1;
}
for(int i=1;i<=t;i++){
st[i].x=rd(); st[i].y=rd();
}
for(int i=1;i<=t;i++)
for(int k=0;k<4;k++)
bfs(st[i].x+dir[0][k],st[i].y+dir[1][k],id(i,k));
nx=rd(); ny=rd();
bfs(nx,ny,4*t+1);
bin[0]=1;
for(int i=1;i<=t;i++) bin[i]=bin[i-1]<<1;
DP();
return 0;
}