LOJ #2733 [JOI2016春季合宿]Sandwiches (DP)
生活随笔
收集整理的這篇文章主要介紹了
LOJ #2733 [JOI2016春季合宿]Sandwiches (DP)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接
https://loj.ac/problem/2733
題解
神仙題……
首先可以觀察到一個結論: 目標塊的兩塊小三明治一定分別是最后和倒數第二個被吃的。
由此我們可以考慮這兩塊誰先被吃。這樣的好處就是,起初我們一個塊被吃的依賴條件是某兩個塊中有一個被吃就行,現在兩個塊中的某一個已經欽定了比它更晚,另一個就一定要比它早,這樣依賴關系就形成了一張圖。
那么有一個\(O(n^4)\)的做法: 對于每一個塊枚舉先吃哪個小三明治,然后DFS求出要先吃這個三明治需要吃掉哪些三明治。
下面還有一個結論: 設對于一個塊\((x,y)\) (第\(x\)行第\(y\)列)我們先吃掉了靠左邊界的塊,那么對于塊\((x,y-1)\) (即它左邊的塊),我們也需要先吃掉靠左邊界的塊,右同理。
推論: 設\(L(x,y)\)是要先取走塊\((x,y)\)靠左邊界的塊需要取走的塊的集合,則\(L(x-1,y)\subset L(x,y)\).
于是枚舉每一行,在這一行中從左到右DFS求\(L\), 從右往左DFS求\(R\), 遍歷過的點無需再遍歷。
總時間復雜度\(O(n^3)\).
代碼
#include<bits/stdc++.h> #define llong long long #define mkpr make_pair using namespace std;const int N = 400; const int INF = 1e8; char a[N+3][N+3]; int vis[N+3][N+3]; int dp0[N+3][N+3],dp1[N+3][N+3]; int n,m;int dfs(int x,int y,int dir) {if(vis[x][y]==-1) {return INF;}else if(vis[x][y]==1) {return 0;}vis[x][y] = -1; int ret = 2;if(a[x][y]=='N'){if(dir==1){if(x>1) {ret += dfs(x-1,y,a[x-1][y]=='N'?1:0);}if(y<m) {ret += dfs(x,y+1,1);}}else{if(x<n) {ret += dfs(x+1,y,a[x+1][y]=='N'?0:1);}if(y>1) {ret += dfs(x,y-1,0);}}}else{if(dir==1){if(x<n) {ret += dfs(x+1,y,a[x+1][y]=='N'?0:1);}if(y<m) {ret += dfs(x,y+1,1);}}else{if(x>1) {ret += dfs(x-1,y,a[x-1][y]=='N'?1:0);}if(y>1) {ret += dfs(x,y-1,0);}}}if(ret<INF) {vis[x][y] = 1;}else ret = INF;return ret; }int main() {scanf("%d%d",&n,&m);for(int i=1; i<=n; i++) scanf("%s",a[i]+1);for(int i=1; i<=n; i++){memset(vis,0,sizeof(vis));for(int j=1; j<=m; j++){dp0[i][j] = dp0[i][j-1]+dfs(i,j,0);if(dp0[i][j]>INF) {dp0[i][j] = INF;}}memset(vis,0,sizeof(vis));for(int j=m; j>=1; j--){dp1[i][j] = dp1[i][j+1]+dfs(i,j,1);if(dp1[i][j]>INF) {dp1[i][j] = INF;}}for(int j=1; j<=m; j++){int ans = min(dp0[i][j],dp1[i][j]);printf("%d ",ans<INF?ans:-1);}puts("");}return 0; }總結
以上是生活随笔為你收集整理的LOJ #2733 [JOI2016春季合宿]Sandwiches (DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LOJ #2734 Luogu P361
- 下一篇: LOJ #2731 [JOI2016春季