CodeForces - 1236D Alice and the Doll(贪心+二分+模拟)
題目鏈接:點擊查看
題目大意:給出一個n*m的矩陣,矩陣中有k個障礙物,在點(1,1)處有一個洋娃娃,洋娃娃每次的行動路線只能是直走或右拐,初始時洋娃娃面朝正右方向,問洋娃娃能否將所有方格都走一遍,并且只走一次(不包括障礙物)
題目分析:n和m的范圍都到達了1e5,如果暴力跑的話時間復雜度能到1e10,肯定會T,那我們有什么好的方法來優化呢?這個題目其實可以借助貪心的思想先分析一波,首先,若整個矩陣中沒有障礙物,那么洋娃娃的行走路線肯定是一個螺旋矩陣的路線,大概就是蛇形填數的那種題目一樣,再就是通過分析可以得到,當洋娃娃可以選擇直走或右拐的時候,肯定會選擇直走而不是右拐,為什么呢?因為洋娃娃一旦右拐,就無法到達原本直走可以到達的方格了,并且隨著洋娃娃轉彎次數的變多,洋娃娃可行走的區域,也就是可移動的矩陣會越來越小,(雖然不會證明,但不難看出),于是我們可以每次貪心移動,讓洋娃娃都到達直走可到達的最遠距離(障礙物或邊界)前停下,然后右拐,并實時維護一直在縮小的可移動矩陣,通過模擬上述過程得到步數,累加后和空白的方塊數量比對一下就能判斷是否達到題目要求了
現在我們的問題就是轉換成怎么樣能比較快速的找到面前的障礙物了,我們可以對于每一行x和每一列y都維護一個數組,當然我是為了方便操作,加上為了讓代碼更加簡潔起見,用了vector來代替數組,儲存每一行以及每一列的障礙物,這樣我們就可以二分了,每次直走的時候都會保證x或y不變,我們只需要二分找到下一個障礙物即可,然后再判斷一下障礙物的位置和可行范圍的大小,就能確定直走可以達到的最大位置了,如此往復模擬上述操作,時間復雜度應該就是nlogn
對了,看網上有人用set維護的障礙物坐標,我感覺沒必要,因為題目已經保證了不會有兩個障礙物在同一個方格上,我還是習慣用vector+sort
對了,這個題目如果按照上述思路基本上是沒問題的,不過還有一個小細節需要注意一下,因為我們在正常情況下每次先直走到頭,然后右拐后再直走到頭,走到最后肯定是無法直走的時候結束循環,但還有一個比較特殊的情況需要我們特判一下,那就是在一開始就需要右拐的情況,若按照上述思路編出來的代碼是無法通過下面的樣例的:
2 1 0
正確答案應該是Yes,但上面的思路給出的答案卻是No,為了解決這種特例,我們可以在一開始加一個first的布爾變量,用來讓起點可以直走,可以直接右拐
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;vector<int>X[N],Y[N];//儲存障礙物,為二分做準備int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int n,m,k;scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=k;i++){int x,y;scanf("%d%d",&x,&y);X[x].push_back(y);Y[y].push_back(x);}for(int i=1;i<=n;i++)sort(X[i].begin(),X[i].end());for(int i=1;i<=m;i++)sort(Y[i].begin(),Y[i].end());int up=0,down=n+1,left=0,right=m+1;LL ans=1;//答案初始化為1,因為題目保證了在點(1,1)處不會有障礙物int x=1,y=1;//當前坐標int pos=0;//當前方向bool first=false;//特判一下起點while(true){int tx,ty;if(pos==0)//→ {int j=lower_bound(X[x].begin(),X[x].end(),y)-X[x].begin();tx=x;if(j==X[x].size())ty=right-1;elsety=min(right-1,X[x][j]-1);up=x;}else if(pos==1)//↓ {int j=lower_bound(Y[y].begin(),Y[y].end(),x)-Y[y].begin();ty=y;if(j==Y[y].size())tx=down-1;elsetx=min(down-1,Y[y][j]-1);right=y;}else if(pos==2)//← {int j=lower_bound(X[x].begin(),X[x].end(),y)-X[x].begin()-1;tx=x;if(j<0)ty=left+1;elsety=max(left+1,X[x][j]+1);down=x;}else if(pos==3)//↑ {int j=lower_bound(Y[y].begin(),Y[y].end(),x)-Y[y].begin()-1;ty=y;if(j<0)tx=up+1;elsetx=max(up+1,Y[y][j]+1);left=y;}if(tx==x&&ty==y&&first)//若走不動了,及時跳出循環break;pos=(pos+1)%4;//走到頭后右拐ans+=abs(tx-x)+abs(ty-y);//答案取一下曼哈頓距離即可x=tx;//迭代y=ty; first=true;//讓洋娃娃可以從起點直接右拐}if(ans==1LL*n*m-k)//記得開longlong,因為n*m到達了1e10printf("Yes\n");elseprintf("No\n");return 0; }?
總結
以上是生活随笔為你收集整理的CodeForces - 1236D Alice and the Doll(贪心+二分+模拟)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 432D Pr
- 下一篇: CodeForces - 979D Ku