天鹅会面
时间限制:1s 内存限制:256MB
题目描述
两头白天鹅生活在一个部分湖面结了冰的湖泊中,湖面的形状为一个长方形,并且被分割成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
题解
是个搜索题,然而不是暴搜。今天的考试过程极其诡异:看题->不会正解,暴力也打不出来->过了一个小时一个字都没打->忽然发现第一题可以做一做->第三题好像也可做->第二题不会->乱搞->第一题和第三题都严重打挂,而第二题居然是全场得分率最高的题……成绩就可想而知了。下午坚持先把自己考试的程序调到满意才去打正解,发现这两个程序虽然不说能过掉,起码能拿大部分分,但是毕竟是自己打挂了也没什么好说的。问题一致出现在考虑不全面上,时间复杂度倒还在其次。
考试已经进行了一个小时的时候,忽然发现这题好像可以用并查集来做……估计全场用了并查集的也就我一个吧……为什么呢?因为问题就是两个天鹅什么时候可以会面,像网络流那样给每个点编号,把能会面的区域合并到一个集合里,再随着时间的推移扩大水面合并集合,当两只天鹅同在一个集合时结束程序,这个算法的正确性显而易见(5S能跑过全部测试点)。但是缺点就在于它的运行时间与答案有关,而且每次都要把很多冰格出队进队,所以说还是个部分分算法。However,由于本蒟蒻忘了每次化冰的时候把两块同时化开的相邻冰合并起来,而只是合并了冰格和这块冰周围的水面,导致水面相连的时间完全不准确,彻底毁掉了这个程序。这种bug样例里当然不会有,凭空想也很难想到,然而却是真实存在的;如果设计程序的时候debug都是随机掉落充满不确定性的,成绩当然也很没有保障了。或许是因为一开始的毫无头绪,到后来的做题过程中稍有些急躁,也没有像平时那样严谨地去验证正确性、填补漏洞,所以出了很大的问题。解决一道题目毕竟是个渐进的过程,如果一眼就有思路也不能算是好题了。今天大概算是大暑假集训以来考试情绪波动最大的一次,也是成绩最差的一次,应该从中吸取教训。
正解是非常优美的搜索。从根本上来说,我们不能把时间效率寄托在答案的大小上,所以一遍bfs预处理出所用冰化开的时间,再用第二遍bfs寻路,以任意一只天鹅为起点,像spfa那样处理出到达某一点的最短时间,搜索结束后到达另一个天鹅的时间就是答案。思路清楚了之后实现并不难,但是由于队列中元素太多导致stl效率很低,需要数组模拟queue;刚开始还不死心,卡了一个小时常数,还是擦边超时,终于放弃改成了数组,又因为数组开得太小折腾了半个小时,最后以不到时限一半的时间过掉。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int sj=1505; int n,m,h[3],z[3],ge,tp1,tp2,tp3,d[sj][sj],dis[sj][sj],tp4; bool ic[sj][sj]; char s[sj]; int qx[sj*sj*10],qy[sj*sj*10],he,ta; inline int bj(int x,int y) { return x>y?x:y; } int main() { scanf("%d%d",&n,&m); ta=he=0; for(int i=1;i<=n;i++) { scanf("%s",s); for(int j=0;j<m;j++) { if(s[j]=='X') { ic[i][j+1]=1; continue; } if(s[j]=='L') { ge++; h[ge]=i; z[ge]=j+1; } d[i][j+1]=0; qx[ta]=i; qy[ta]=j+1; ta++; } } while(he<ta) { tp1=qx[he]; tp2=qy[he]; tp3=d[tp1][tp2]; he++; if(tp1!=1&&ic[tp1-1][tp2]) { ic[tp1-1][tp2]=0; d[tp1-1][tp2]=tp3+1; qx[ta]=tp1-1; qy[ta]=tp2; ta++; } if(tp1!=n&&ic[tp1+1][tp2]) { ic[tp1+1][tp2]=0; d[tp1+1][tp2]=tp3+1; qx[ta]=tp1+1; qy[ta]=tp2; ta++; } if(tp2!=1&&ic[tp1][tp2-1]) { ic[tp1][tp2-1]=0; d[tp1][tp2-1]=tp3+1; qx[ta]=tp1; qy[ta]=tp2-1; ta++; } if(tp2!=m&&ic[tp1][tp2+1]) { ic[tp1][tp2+1]=0; d[tp1][tp2+1]=tp3+1; qx[ta]=tp1; qy[ta]=tp2+1; ta++; } } ta=he=0; memset(dis,0x3f,sizeof(dis)); dis[h[1]][z[1]]=0; qx[ta]=h[1]; qy[ta]=z[1]; ta++; ic[h[1]][z[1]]=1; while(he<ta) { tp1=qx[he]; tp2=qy[he]; tp3=dis[tp1][tp2]; ic[tp1][tp2]=0; he++; tp4=bj(tp3,d[tp1-1][tp2]); if(tp1!=1&&dis[tp1-1][tp2]>tp4) { dis[tp1-1][tp2]=tp4; if(!ic[tp1-1][tp2]) { qx[ta]=tp1-1; qy[ta]=tp2; ta++; ic[tp1-1][tp2]=1; } } tp4=bj(tp3,d[tp1+1][tp2]); if(tp1!=n&&dis[tp1+1][tp2]>tp4) { dis[tp1+1][tp2]=tp4; if(!ic[tp1+1][tp2]) { qx[ta]=tp1+1; qy[ta]=tp2; ta++; ic[tp1+1][tp2]=1; } } tp4=bj(tp3,d[tp1][tp2-1]); if(tp2!=1&&dis[tp1][tp2-1]>tp4) { dis[tp1][tp2-1]=tp4; if(!ic[tp1][tp2-1]) { qx[ta]=tp1; qy[ta]=tp2-1; ta++; ic[tp1][tp2-1]=1; } } tp4=bj(tp3,d[tp1][tp2+1]); if(tp2!=m&&dis[tp1][tp2+1]>tp4) { dis[tp1][tp2+1]=tp4; if(!ic[tp1][tp2+1]) { qx[ta]=tp1; qy[ta]=tp2+1; ta++; ic[tp1][tp2+1]=1; } } } printf("%d",dis[h[2]][z[2]]); return 0; }
沐阳光,纳锐气,展青春风采。
砺心志,继绝学,逞一代天骄。