天鵝會面
題目描述
兩頭白天鵝生活在一個部分湖面結了冰的湖泊中,湖面的形狀爲一個長方形,並且被分割成R行C列的小方格,某些方格中結了冰,這樣的方格稱之爲冰格,其餘的方格稱之爲水格。冬天過去了,湖面上的冰漸漸開始溶解了,每一天與水相鄰的冰格就將消融而轉化爲水格。所謂兩個方格相鄰是指它們在水平或垂直方向有公共邊,兩個呈對角的方格是不相鄰的,下圖給出樣例數據的演化過程。
白天鵝只能在水中沿水平或垂直方向遊動,寫一個程序判斷多少天后兩隻白天鵝才能夠相會。
【輸入格式】
輸入文件第一行包含兩個用空格隔開的整數R和C,其中1 ≤ R, C ≤ 1500,接下來的R行每行包含C個字符,描述湖面的初始狀態,‘·’表示水格,‘ X’表示冰格,‘ L’表示一隻白天鵝。
【輸出格式】
輸出文件僅一行包含一個整數表示兩隻白天鵝等到相鄰那一天所需的天數。
【輸入樣例】
8 17
...XXXXXX..XX.XXX
....XXXXXXXXX.XXX
...XXXXXXXXXXXX..
..XXXXX.LXXXXXX..
.XXXXXX..XXXXXX..
XXXXXXX...XXXX...
..XXXXX...XXX....
....XXXXX.XXXL...
【輸出樣例】
2
Hint
30%數據1 ≤ R《400.1 ≤ C《300
100%其中1 ≤ R, C ≤ 1500
看題目就可以感覺到是廣搜,不過需要一些剪枝和優化。一定要先讀清題,天鵝走是不耗費時間的,也就是說,只要兩隻天鵝被水域聯通,就可以立刻遇見對方,所以限制相遇時間的是冰的融化程度。剛開始思路偏了,想從兩隻天鵝同時搜。。。
正確的做法是預處理出來冰的融化時間,然後以一隻天鵝爲起點進行廣搜,還有一種類似SPFA的優化,進隊前判斷是否已經在隊列裏,但是我的方法加了優化會錯誤更新答案,所以卡常低空掠過。。。
注意:天鵝不需要在同一點才能相遇,相鄰就可以了。珍愛生命,遠離STL!!!內存超限少不了,循環隊列大法好。
代碼如下
#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 1501
#define maxx 20695015
#define fastcall __attribute__((optimize("-O3")))
#define IL __inline__ __attribute__((always_inline))//我也是迫不得已
using namespace std;
fastcall IL int read()
{ char c=getchar();int x=0,y=1;
while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
fastcall IL int m_max(int x,int y){return x>y?x:y;}
const int mod=20695013;//模運算太慢,卡時限
int n,m,cnt=0,mp[maxn][maxn],tail,head,steps[maxn][maxn];
struct node{int x,y,step;}q[maxx],tt[3];
fastcall IL void bfs1()//預處理融化時間
{ while(head<=tail)
{ node u=q[head];++head;
if(u.x<n&&mp[u.x+1][u.y]==-1) mp[u.x+1][u.y]=2,steps[u.x+1][u.y]=u.step+1,q[++tail]=(node){u.x+1,u.y,u.step+1};
if(u.x>1&&mp[u.x-1][u.y]==-1) mp[u.x-1][u.y]=2,steps[u.x-1][u.y]=u.step+1,q[++tail]=(node){u.x-1,u.y,u.step+1};
if(u.y>1&&mp[u.x][u.y-1]==-1) mp[u.x][u.y-1]=2,steps[u.x][u.y-1]=u.step+1,q[++tail]=(node){u.x,u.y-1,u.step+1};
if(u.y<m&&mp[u.x][u.y+1]==-1) mp[u.x][u.y+1]=2,steps[u.x][u.y+1]=u.step+1,q[++tail]=(node){u.x,u.y+1,u.step+1};
}
}
fastcall IL void bfs()
{ head=0;tail=0;
q[tail]=tt[1];++tail;//STL太慢,爲了節約內存用了循環隊列
while(head!=tail)
{ node u=q[head];head++;if(head==mod) head=0;//枚舉單點就足夠,不需要枚舉一條直線上的點,因爲會由點推出路徑
int tmp1=m_max(u.step,steps[u.x+1][u.y]),tmp2=m_max(u.step,steps[u.x-1][u.y]),tmp3=m_max(u.step,steps[u.x][u.y+1]),tmp4=m_max(u.step,steps[u.x][u.y-1]);
if(u.x<n&&mp[u.x+1][u.y]>tmp1)//像SPFA一樣鬆弛
{ mp[u.x+1][u.y]=tmp1;
q[tail]=(node){u.x+1,u.y,tmp1};++tail;
if(tail==mod) tail=0;//if(!ok[u.x+1][u.y]) ok[u.x+1][u.y]=1,優化大概是這樣的,但我的方法不行
}
if(u.x>1&&mp[u.x-1][u.y]>tmp2)
{ mp[u.x-1][u.y]=tmp2;
q[tail]=(node){u.x-1,u.y,tmp2};++tail;
if(tail==mod) tail=0;//if(!ok[u.x-1][u.y]) ok[u.x-1][u.y]=1,
}
if(u.y>1&&mp[u.x][u.y-1]>tmp4)
{ mp[u.x][u.y-1]=tmp4;
q[tail]=(node){u.x,u.y-1,tmp4};++tail;
if(tail==mod) tail=0;//if(!ok[u.x][u.y-1]) ok[u.x][u.y-1]=1,
}
if(u.y<m&&mp[u.x][u.y+1]>tmp3)
{ mp[u.x][u.y+1]=tmp3;
q[tail]=(node){u.x,u.y+1,tmp3};++tail;
if(tail==mod) tail=0;//if(!ok[u.x][u.y+1]) ok[u.x][u.y+1]=1,
}
}
}
int main()
{ //freopen("swan.in","r",stdin);
//freopen("swan.out","w",stdout);
head=1;tail=0;char c;
n=read();m=read();
for(int i=1;i<=n;++i)
{ for(int j=1;j<=m;++j)
{ c=getchar();while(c!='.'&&c!='L'&&c!='X') c=getchar();
if(c=='.') mp[i][j]=2,q[++tail]=(node){i,j,0};
else if(c=='L'){q[++tail]=(node){i,j,0};mp[i][j]=2;++cnt;if(cnt==1) steps[i][j]=0;tt[cnt]=(node){i,j,0};}
else mp[i][j]=-1;
}
}
bfs1();
memset(mp,0x7f,sizeof(mp));
bfs();
printf("%d",mp[tt[2].x][tt[2].y]);
return 0;
}