原文链接http://www.cnblogs.com/zhouzhendong/p/8371735.html
题目传送门 - BZOJ3393
题意概括
直接看原题的翻译吧,很容易懂的。
题解
我不知道这道题为什么放在网络流里面。
我也不知道网上为什么几乎都是SPFA。
这题就是一个裸的广搜啊啊啊。
20ms通过。
我们来考虑广搜。
只有改变方向是要花费的。
所以,我们入队的时候是一条线上的一起入队。
具体看我的pushnew函数。
然后主要的BFS循环内,只要扩展转弯就可以了(参见代码)。
我们考虑到,我这样做会导致在一个位置上进行多次转弯。
多次转弯,貌似是错的,但是由于本题特殊,这样一定是亏的,不会作为最优方案。
大概分成两种情况。
我们考虑如果只转了一次,显然是对的。
如果转了3次及以上,显然是亏的。
如果转了2次,只有可能:
1.原方向行进,显然是亏的。
2.原路返回,显然也是亏的。(自己脑补一下)
还有一个疑惑:比如下图的路线是否可能为最优路线(我的算法有可能会搜出这样的路线):
于是在(0,5)这个位置的镜子显然不对了。
但是这个显然不会是最优路线,直接挂掉。
代码
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int WH=105,N=4*WH*WH;
int w,h,S,E,dis[N],vis[N],q[N],head,tail;
char g[WH][WH];
int dx[4]={-1, 0, 1, 0};
int dy[4]={ 0, 1, 0,-1};
char gc(){
char ch=getchar();
while (ch!='.'&&ch!='*'&&ch!='C')
ch=getchar();
return ch;
}
bool check(int x,int y){
return 1<=x&&x<=w&&1<=y&&y<=h&&g[x][y]!='*';
}
int HA(int dir,int x,int y){
return dir*w*h+(x-1)*h+y-1;
}
void HB(int v,int &dir,int &x,int &y){
dir=v/w/h,v%=w*h,x=v/h+1,y=v%h+1;
}
bool covered(int v1,int v2){
return v1%(w*h)==v2%(w*h);
}
void pushnew(int dir,int x,int y,int d){
while (check(x,y)){
int i=HA(dir,x,y);
if (vis[i])
break;
vis[i]=1,dis[i]=d;
q[++tail]=i;
x+=dx[dir],y+=dy[dir];
}
}
int main(){
scanf("%d%d",&h,&w);
for (int i=1;i<=w;i++)
for (int j=1;j<=h;j++)
g[i][j]=gc();
S=E=-1;
for (int i=1;i<=w;i++)
for (int j=1;j<=h;j++)
if (g[i][j]=='C')
if (!~S)
S=(i-1)*h+j-1;
else
E=(i-1)*h+j-1;
memset(vis,0,sizeof vis);
head=tail=0;
for (int i=0;i<4;i++)
dis[HA(i,E/h+1,E%h+1)]=w*h;
for (int i=0;i<4;i++)
pushnew(i,S/h+1,S%h+1,0);
while (head<tail){
int v=q[++head],dir,x,y;
if (covered(v,E))
break;
HB(v,dir,x,y);
pushnew((dir+1)%4,x,y,dis[v]+1);
pushnew((dir+3)%4,x,y,dis[v]+1);
}
int ans=w*h;
for (int i=0;i<4;i++)
ans=min(ans,dis[HA(i,E/h+1,E%h+1)]);
printf("%d",ans);
return 0;
}