日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CodeForces - 1335F Robots on a Grid(拓扑找环+反向dfs/倍增)

發布時間:2024/4/11 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CodeForces - 1335F Robots on a Grid(拓扑找环+反向dfs/倍增) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一個 n * m 的矩陣,矩陣的每一個格子都有一個顏色,顏色非黑即白,除此之外每個格子還有一個指令,分別為:

  • ' U ':向上一個單位
  • ' D ':向下一個單位
  • ' R ':向右一個單位
  • ' L ':向左一個單位
  • 每個格子都可以放置機器人,對于每個機器人而言,每一秒都會遵循格子上的指令行走,換句話說,機器人會永不停止的行走,現在問,如何放置機器人,可以使得矩陣中機器人的數量最多,且互相永遠不會沖突,即任意時刻每個格子里至多有只能一個機器人,在滿足矩陣中機器人數量最多的前提下,如何擺放可以使得在黑色格子上的機器人最多,分別輸出這兩個答案

    題目分析:這個題目兩個思路,一種思路比較好想,但是細節較多,碼量較大,另一種思路需要一定的思維,實現簡單,碼量小

    先從第一種思路說起,因為機器人會永不停止的行走,就說明矩陣中一定存在著首尾相接的環,顯然所有環的長度之和就是ans1了,也可以知道了ans1與顏色無關,對于ans2我們需要多考慮一點東西:

    ?在上面這個情況中,點1和點2已經組成了一個首尾相接的環路,所以ans1顯然為 2 ,就不多贅述了,但是加上顏色的限制,如果點1和點2同為白色,但是點3為黑色,那么初始時最優的擺放策略肯定是擺在點3和點2,因為這樣既能滿足ans1=2,且ans2=1,這種情況該如何考慮呢?對于環上的任意一個節點開始,沿著反向邊進行遍歷,跑出?dis 距離數組就行了,顯然如果在這樣一個整體中,如果最終不想沖突的話,dis[ i ] % len 的位置上至多只能有一個機器人,此處的 len 為首位相接的環路長度

    想清楚上面 dis[ i ] % len 這個地方后,實現就好了,重新捋一下這個題的過程,首先整個矩陣可以視為一個 n * m 個結點和 n * m 條邊組成的有向圖,既然是有向圖,就可以拓撲找環,根據拓撲排序的性質將整個圖處理到只剩下首尾相接的環路,此后對于每個環路而言,找到上面的任意一個結點開始,反向 dfs 跑出 dis 數組,然后判斷就好了

    細節較多,代碼如下:

    #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;const int b[4][2]={0,1,0,-1,1,0,-1,0};int mp[150];int n,m,len,du[N],deep[N];//du:入度 deep:在環上的相對位置 len:環的長度 string maze[N],color[N];vector<int>node[N],out[N];//正向邊與反向邊vector<int>black[N];//black[i]:以點 i 為根節點的環中所牽連的黑點 bool vis[N],flag[N];//vis:是否在環上 flag:找黑點上機器人時用 inline void addedge(int u,int v) {node[u].push_back(v);out[v].push_back(u);du[v]++; }inline int get_id(int x,int y) {return x*m+y; }void topo()//拓撲找環 {queue<int>q;for(int i=0;i<n*m;i++)if(!du[i])q.push(i);while(q.size()){int u=q.front();q.pop();for(auto v:node[u])if(--du[v]==0)q.push(v);} }void dfs(int u,int rt,int dep) {vis[u]=true;deep[u]=dep;if(color[u/m][u%m]=='0')black[rt].push_back(u);for(auto v:out[u]){if(vis[v]){len=deep[u];continue;}dfs(v,rt,dep+1);} }inline void init() {for(int i=0;i<n*m;i++){node[i].clear();out[i].clear();black[i].clear();vis[i]=flag[i]=du[i]=0;} }int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false);mp['R']=0,mp['L']=1,mp['D']=2,mp['U']=3;int w;cin>>w;while(w--){scanf("%d%d",&n,&m);init();for(int i=0;i<n;i++)cin>>color[i];for(int i=0;i<n;i++)cin>>maze[i];for(int i=0;i<n;i++)for(int j=0;j<m;j++){int k=mp[maze[i][j]];addedge(get_id(i,j),get_id(i+b[k][0],j+b[k][1]));}topo();int ans1=0,ans2=0;for(int i=0;i<n*m;i++)if(du[i]&&!vis[i])//在環上且沒遍歷過,遍歷一遍這個環{dfs(i,i,1);ans1+=len;for(auto v:black[i])if(!flag[deep[v]%len]){flag[deep[v]%len]=true;ans2++;}for(auto v:black[i])flag[deep[v]%len]=false;}printf("%d %d\n",ans1,ans2);}return 0; }

    下面說一下第二種思路,假如兩個機器人會沖突的話,也就是說在某個時刻,某個格子中同時出現了兩個機器人,那么在接下來的移動過程中,顯然這兩個機器人的路徑將保持一致,我們可以先假設 n * m 個格子中初始時都有一個機器人,先讓這些機器人運動 n * m 秒,甚至更多,因為 n * m 的一個矩陣,最大可以形成的一個首尾相接的環路長度就是 n * m ,所以先讓所有機器人都運動 n * m 秒后,該重合的機器人都已經重合了,并且不難統計每個位置中有多少個來自黑格的機器人,此時矩陣中仍然有機器人的地方,就說明這個位置是首尾相接的環,那么ans1++,如果這個地方至少有一個來自黑格的機器人,那就說明來到這個位置的機器人初始時可以擺在黑格上,即ans2++

    實現的話肯定不是暴力模擬 n * m 秒,可以利用倍增,首先將 n * m 個格子按照 0 ~ n * m - 1 編號,那么 dp[ i ][ j ] 就代表編號為 i 的點走 2^j 步可以到達的地方,這里類比于樹上倍增就好,剩下的實現起來就比較簡單了

    代碼:

    #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;const int b[4][2]={0,1,0,-1,1,0,-1,0};int mp[150];string maze[N],color[N];int dp[N][20],n,m,num[N][2];//num[i][0]:black num[i][1]:whiteinline int get_id(int x,int y) {return x*m+y; }int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false);mp['R']=0,mp['L']=1,mp['D']=2,mp['U']=3;int w;cin>>w;while(w--){scanf("%d%d",&n,&m);for(int i=0;i<n*m;i++)num[i][0]=num[i][1]=0;int limit=log2(n*m)+1;for(int i=0;i<n;i++)cin>>color[i];for(int i=0;i<n;i++)cin>>maze[i];for(int i=0;i<n;i++)for(int j=0;j<m;j++){int k=mp[maze[i][j]];dp[get_id(i,j)][0]=get_id(i+b[k][0],j+b[k][1]);}for(int j=1;j<=limit;j++)for(int i=0;i<n*m;i++)dp[i][j]=dp[dp[i][j-1]][j-1];for(int i=0;i<n;i++)for(int j=0;j<m;j++)num[dp[get_id(i,j)][limit]][color[i][j]-'0']++;int ans1=0,ans2=0;for(int i=0;i<n*m;i++){ans1+=!!(num[i][1]+num[i][0]);//大佬代碼學到的,判斷一個數是否非零,tqlans2+=!!num[i][0];}printf("%d %d\n",ans1,ans2);}return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的CodeForces - 1335F Robots on a Grid(拓扑找环+反向dfs/倍增)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。