Luogu P1979 华容道
心血来潮水篇博客
2019.9.25
一开始瞄着30分打了个bfs暴力
一测60(开心)
WA了两个点(是我忘记判断起点=终点了。。)
改了就70
贴一下
#include<cstdio>
#include<cstring>
using namespace std;
int ans=-1,tx,ty;
int n,m,q,a[1010][1010];
struct nod1{int ex,ey,sx,sy,t;}d[5000100];
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int f[110][110][110][110];
void bfs()
{
int head=1,tail=2;
d[1].t=0;
f[d[1].ex][d[1].ey][d[1].sx][d[1].sy]=1;
while(head!=tail)
{
int x=d[head].ex;
int y=d[head].ey;
for(int i=0;i<4;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(a[xx][yy]==0||xx<1||yy<1||xx>n||yy>m)continue;
d[tail]=d[head];
if(xx==d[head].sx&&yy==d[head].sy)
{
d[tail].sx=x;d[tail].sy=y;
if(x==tx&&y==ty)
{
ans=d[head].t+1;
return ;
}
}
d[tail].ex=xx;
d[tail].ey=yy;
d[tail].t=d[head].t+1;
if(f[d[tail].ex][d[tail].ey][d[tail].sx][d[tail].sy]==1)continue;
f[d[tail].ex][d[tail].ey][d[tail].sx][d[tail].sy]=1;
tail++;
}
head++;
}
}
int main()
{
//freopen("ddd.in","r",stdin);
//freopen("mee.out","w",stdout);
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=1;i<=q;i++)
{
scanf("%d %d %d %d %d %d",&d[1].ex,&d[1].ey,&d[1].sx,&d[1].sy,&tx,&ty);
if(d[1].sx==tx&&d[1].sy==ty)
{
printf("0\n");continue;
}
ans=-1;
for(int l1=1;l1<=n;l1++)
for(int l2=1;l2<=m;l2++)
for(int l3=1;l3<=n;l3++)
for(int l4=1;l4<=m;l4++)
f[l1][l2][l3][l4]=0;
bfs();
printf("%d\n",ans);
}
}
然后我试图看懂题解
然后放弃了…
2019.9.28
好 我卷土重来了
一篇详细的题解
明白了 思路清晰了
码了一会 ->80
QAQ查出来我是bfs不判起点=终点
然后A了
顺便把思路打在代码里了
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int maxn=0x3f3f3f3f;
int a[1010][1010];
int dx[5]={-1,1,0,0,0};
int dy[5]={0,0,-1,1,0};//上下左右
//最后的两个零是为了check自己啊哈
int v[1010][1010];
struct nod1{int x,y,t;}d[100100];
int vv[100100],dis[100100],f[100100];
struct nod2{int y,c,next;}b[100100];
int first[100100],len=0;
int ans=0x3f3f3f3f,n,m,q;
int nowx,nowy,bx,by,gox,goy;
void ins(int x,int y,int c)
{
len++;
b[len].y=y;
b[len].c=c;
b[len].next=first[x];
first[x]=len;
}
int id(int x,int y,int k)
{
return ((x-1)*m+y)*4-(4-k);
}
int check(int x,int y,int k)
{
int xx=x+dx[k];
int yy=y+dy[k];
if(xx<1||xx>n||yy<1||yy>m||a[xx][yy]==0)return 0;
return 1;
}
int bfs(int sx,int sy,int nox,int noy,int ex,int ey)
//出发点 不能走 终点
{
if(sx==ex&&sy==ey)return 0;//!!!!!WA成80的原因 记住!!!
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
v[i][j]=0;
v[sx][sy]=1;
d[1].x=sx;d[1].y=sy;
d[1].t=0;
int head=1,tail=2;
while(head<tail)
{
int x=d[head].x,y=d[head].y;
for(int i=0;i<4;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx==ex&&yy==ey)return d[head].t+1;
if(v[xx][yy]==1||check(x,y,i)==0||(xx==nox&&yy==noy))continue;
v[xx][yy]=1;
d[tail].t=d[head].t+1;
d[tail].x=xx;
d[tail].y=yy;
tail++;
}
head++;
}
return maxn;
}
void pre()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]==0)continue;
for(int k=0;k<4;k++)
{
if(check(i,j,k)==0)continue;
for(int p=k+1;p<4;p++)
{
if(check(i,j,p)==0)continue;
int step=bfs(i+dx[k],j+dy[k],i,j,i+dx[p],j+dy[p]);
if(step==maxn)continue;
ins(id(i,j,k),id(i,j,p),step);
ins(id(i,j,p),id(i,j,k),step);
}
}
}
}//四个方向转换
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]==0)continue;
if(check(i,j,1))
{
ins(id(i,j,1),id(i+1,j,0),1);
ins(id(i+1,j,0),id(i,j,1),1);
}
if(check(i,j,3))
{
ins(id(i,j,3),id(i,j+1,2),1);
ins(id(i,j+1,2),id(i,j,3),1);
}
}
}//上下/左右换
}
void find()
{
int head=1,tail=1;
for(int i=1;i<=n*m*4;i++)
{
dis[i]=0x3f3f3f3f;vv[i]=0;
}
for(int i=0;i<4;i++)
{
if(check(nowx,nowy,i))
{
int xx=nowx+dx[i];
int yy=nowy+dy[i];
int step=bfs(bx,by,nowx,nowy,xx,yy);
if(step==maxn)continue;
int ip=id(nowx,nowy,i);
f[tail]=ip;
dis[ip]=step;
vv[ip]=1;
tail++;
}
}//白格子先走到现在格子附近
while(head<tail)
{
int x=f[head];
for(int i=first[x];i;i=b[i].next)
{
int y=b[i].y;
if(dis[y]>dis[x]+b[i].c)
{
dis[y]=dis[x]+b[i].c;
if(vv[y]==0)
{
vv[y]=1;
f[tail]=y;
tail++;
}
}
}
head++;
vv[x]=0;
}//spfa
ans=0x3f3f3f3f;
for(int i=0;i<4;i++)
{
if(check(gox,goy,i)==0)continue;
ans=min(dis[id(gox,goy,i)],ans);
}
if(ans==maxn)
printf("-1\n");
else
printf("%d\n",ans);
}
int main()
{
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
pre();
//先预处理出
//1.每个格子上下左右转换的步数,建边
//2.每个格子:白格子在下的状态 和 这个格子下一个格子(x+1,y)白格子在上的状态 建值=1的边[上下交换]
//3.每个格子:白格子在右的状态 和 这个格子右一个格子(x,y+1)白格子在左的状态 建值=1的边[左右交换]
for(int i=1;i<=q;i++)
{
scanf("%d %d %d %d %d %d",&bx,&by,&nowx,&nowy,&gox,&goy);
if(nowx==gox&&nowy==goy)
{
printf("0\n");
continue;
}
if(check(nowx,nowy,4)==0||check(gox,goy,4)==0)
{
printf("-1\n");
continue;
}
find();
//先把白格子跑到目标格子附近四个格子(bfs处理步数),再开始跑spfa
}
}
//本题是状态做点 步数为边权建图(好厉害!)
//一定要记住判断起点等于终点噢