2018/7/16 YMOI模擬 NOIP2013D2T3華容道

来源:https://www.cnblogs.com/fl0w3r/archive/2018/07/16/9320625.html
-Advertisement-
Play Games

題目描述 Description 小 B 最近迷上了華容道,可是他總是要花很長的時間才能完成一次。於是,他想到用編程來完成華容道:給定一種局面,華容道是否根本就無法完成,如果能完成,最少需要多少時間。 小 B 玩的華容道與經典的華容道游戲略有不同,游戲規則是這樣的: 在一個 n*m 棋盤上有 n*m ...


題目描述 Description

小 B 最近迷上了華容道,可是他總是要花很長的時間才能完成一次。於是,他想到用編程來完成華容道:給定一種局面,華容道是否根本就無法完成,如果能完成,最少需要多少時間。
小 B 玩的華容道與經典的華容道游戲略有不同,游戲規則是這樣的:

  1. 在一個 n*m 棋盤上有 n*m 個格子,其中有且只有一個格子是空白的,其餘 n*m-1個格子上每個格子上有一個棋子,每個棋子的大小都是 1*1 的;
  2. 有些棋子是固定的,有些棋子則是可以移動的;
  3. 任何與空白的格子相鄰(有公共的邊)的格子上的棋子都可以移動到空白格子上。 游戲的目的是把某個指定位置可以活動的棋子移動到目標位置。

給定一個棋盤,游戲可以玩 q 次,當然,每次棋盤上固定的格子是不會變的,但是棋盤上空白的格子的初始位置、指定的可移動的棋子的初始位置和目標位置卻可能不同。第 i 次玩的時候,空白的格子在第 EX_i 行第 EY_i 列,指定的可移動棋子的初始位置為第 SX_i 行第 SY_i 列,目標位置為第 TX_i 行第 TY_i 列。
假設小 B 每秒鐘能進行一次移動棋子的操作,而其他操作的時間都可以忽略不計。請你告訴小 B 每一次游戲所需要的最少時間,或者告訴他不可能完成游戲。

輸入描述 Input Description

第一行有 3 個整數,每兩個整數之間用一個空格隔開,依次表示 n、m 和 q;
接下來的 n 行描述一個 n*m 的棋盤,每行有 m 個整數,每兩個整數之間用一個空格隔開,每個整數描述棋盤上一個格子的狀態,0 表示該格子上的棋子是固定的,1 表示該格子上的棋子可以移動或者該格子是空白的。
接下來的 q 行,每行包含 6 個整數依次是 EX_i、EY_i、SX_i、SY_i、TX_i、TY_i,每兩個整數之間用一個空格隔開,表示每次游戲空白格子的位置,指定棋子的初始位置和目標位置。

輸出描述 Output Description

輸出有 q 行,每行包含 1 個整數,表示每次游戲所需要的最少時間,如果某次游戲無法完成目標則輸出-1。

樣例輸入 Sample Input

3 4 2 
0 1 1 1 
0 1 1 0 
0 1 0 0 
3 2 1 2 2 2 
1 2 2 2 3 2

樣例輸出 Sample Output


-1

數據範圍及提示 Data Size & Hint

【樣例說明】
棋盤上劃叉的格子是固定的,紅色格子是目標位置,圓圈表示棋子,其中綠色圓圈表示目標棋子。
第一次游戲,空白格子的初始位置是 (3, 2)(圖中空白所示),游戲的目標是將初始位置在(1, 2)上的棋子(圖中綠色圓圈所代表的棋子)移動到目標位置(2, 2)(圖中紅色的格子)上。
移動過程如下:

第二次游戲,空白格子的初始位置是(1, 2)(圖中空白所示),游戲的目標是將初始位置在(2, 2)上的棋子(圖中綠色圓圈所示)移動到目標位置 (3, 2)上。

要將指定塊移入目標位置,必須先將空白塊移入目標位置,空白塊要移動到目標位置,必然是從位置(2,2)上與當前圖中目標位置上的棋子交換位置,之後能與空白塊交換位置的只有當前圖中目標位置上的那個棋子,因此目標棋子永遠無法走到它的目標位置,游戲無法完成。

【數據範圍】
對於 30%的數據,1 ≤ n, m ≤ 10,q = 1; 
對於 60%的數據,1 ≤ n, m ≤ 30,q ≤ 10; 
對於 100%的數據,1 ≤ n, m ≤ 30,q ≤ 500。

——————————————————————————————————————————————————————————————————————————

思路一(雖然沒錯但是會TLE)

一看到題目,聯想到以前做過的八數位。於是可以想到把空白塊當作可以自由移動的單位進行BFS。由於想不到什麼優化措施,所以就敲了一段大爆搜……雖然TLE是意料之中,但是沒想到竟然能拿到70分(那這就說明我離正解不遠了/誤)

蒟蒻的大爆搜就別看了qwq

——————————————————————————————————————————————————————————————————————————

思路二(正解)

整理一下為什麼思路一的BFS是錯的。

在一個規模較小的數據範圍內,思路一的BFS是可以在1s內得出結論的……但是很不幸,雖然出題人很善良的給了70分(是不是沒卡掉),但是爆搜還是沒有前途的;

思路一的BFS缺陷就是,白塊是以一種玄妙不可預測的路線行進的(誤)。在搜索的時候會浪費很多時間在根本不可能的情況上(不做無法實現的夢)。

所以在冥(ming)思(le)苦(ti)想(jie)以後想到了絕妙的演算法!

對於最優的操作,有一個前提是空白塊一定要先移動到欽點塊的旁邊。然後空白塊和欽點塊再作為一個整體移動。

空白塊和欽點塊的移動可以用SPFA來求最短路徑。建圖的方法就是把空白塊和欽點塊的位置的狀態看作一個點,再把每個狀態之間互相轉換的過程看作邊,在這個圖裡跑一邊SPFA就可以輕鬆求出正解!

以下是蒟蒻敲了一個下午的代碼

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<cstring>
  5 using namespace std;
  6 #define MAXN 31
  7 #define MAXM 40001
  8 #define INF 0x3f3f3f3f
  9 int n,m,q,num[MAXN][MAXN][5],tot,cnt,head[MAXM],vis[MAXN][MAXN],ex,ey,sx,sy,tx,ty,dis[MAXM],used[MAXM],mp[MAXN][MAXN];
 10 const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
 11 struct Edge
 12 {
 13     int to,dis,next;
 14 }e[MAXM];
 15 struct ZT{int x,y,steps;};
 16 void add(int from,int to,int dis)
 17 {
 18     e[++cnt].next=head[from];
 19     e[cnt].to=to;
 20     e[cnt].dis=dis;
 21     head[from]=cnt;
 22 }
 23 int bfs(int ax,int ay,int bx,int by,int cx,int cy)
 24 {
 25     if(ax==bx&&ay==by) return 0;
 26     memset(vis,0,sizeof(vis));
 27     queue<ZT>Q;
 28     while(!Q.empty()) Q.pop();
 29     Q.push((ZT){ax,ay,0});
 30     vis[ax][ay]=vis[cx][cy]=1;
 31     while(!Q.empty())
 32     {
 33         ZT u=Q.front();Q.pop();
 34         if(u.x==bx&&u.y==by) return u.steps;
 35         for(int i=0;i<4;i++)
 36         {
 37             int x=u.x+dx[i],y=u.y+dy[i];
 38             if(x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]&&!vis[x][y])
 39             {
 40                 Q.push((ZT){x,y,u.steps+1});
 41                 vis[x][y]=1;
 42                 if(x==bx&&y==by) return u.steps+1;
 43             }
 44         }
 45     }
 46     return INF;
 47 }
 48 void init()
 49 {
 50     for(int i=1;i<=n;i++)
 51         for(int j=1;j<=m;j++)
 52             for(int k=0;k<4;k++)
 53                 if(mp[i][j]&&mp[i+dx[k]][j+dy[k]])
 54                     num[i][j][k]=++tot;
 55     for(int i=1;i<=n;i++)
 56         for(int j=1;j<=m;j++)
 57             for(int k=0;k<4;k++)
 58                 if(num[i][j][k])
 59                     add(num[i][j][k],num[i+dx[k]][j+dy[k]][k^1],1);
 60     for(int i=1;i<=n;i++)
 61         for(int j=1;j<=m;j++)
 62             for(int k=0;k<4;k++)
 63                 for(int l=0;l<4;l++)
 64                     if(l!=k&&num[i][j][k]&&num[i][j][l])
 65                         add(num[i][j][k],num[i][j][l],bfs(i+dx[k],j+dy[k],i+dx[l],j+dy[l],i,j));
 66 }
 67 int spfa()
 68 {
 69     queue<int>Q;
 70     if(sx==tx&&sy==ty) return 0;
 71     for(int i=1;i<=tot;i++) dis[i]=INF;
 72     for(int k=0;k<4;k++)
 73     {
 74         if(num[sx][sy][k])
 75         {
 76             dis[num[sx][sy][k]]=bfs(ex,ey,sx+dx[k],sy+dy[k],sx,sy);
 77             Q.push(num[sx][sy][k]);
 78         }
 79     }
 80     while(!Q.empty())
 81     {
 82         int u=Q.front();Q.pop();
 83         used[u]=0;
 84         for(int i=head[u];i;i=e[i].next)
 85         {
 86             int v=e[i].to;
 87             if(dis[v]>dis[u]+e[i].dis)
 88             {
 89                 dis[v]=dis[u]+e[i].dis;
 90                 if(!used[v])
 91                 {
 92                     Q.push(v);
 93                     used[v]=1;
 94                 }
 95             }
 96         }
 97     }
 98     int ans=INF;
 99     for(int k=0;k<4;k++)
100     {
101         if(num[tx][ty][k]) ans=min(ans,dis[num[tx][ty][k]]);
102     }
103     return ans==INF?-1:ans;
104 }
105 int main()
106 {
107     scanf("%d%d%d",&n,&m,&q);
108     for(int i=1;i<=n;i++)
109         for(int j=1;j<=m;j++)
110             scanf("%d",&mp[i][j]);
111     init();
112     while(q--)
113     {
114         scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
115         printf("%d\n",spfa());
116     }
117     return 0;
118 }
118行orz

 


這道題做的我要死了orz

順便吐槽一下為什麼NOIP2013D2前兩道都是普及的水題,到最後一道題就這麼難orz

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • javap: 反編譯工具, 可用來查看java編譯器生成的位元組碼 參數摘要: -help 幫助 -l 輸出行和變數的表 -public 只輸出public方法和域 -protected 只輸出public和protected類和成員 -package 只輸出包,public和protected類和成 ...
  • 1、構造方法 定義:與類同名沒有返回值的方法稱為構造方法; public class test1 {private String name;private int age;public test1(){} } 上面的test1()是預設構造方法,即使沒有定義java虛擬機在運行的時候也會自動生成, ...
  • CountDownLatch允許一個或多個線程等待其他線程完成操作。 假如有這樣一個需求:我們需要解析一個Excel里多個sheet的數據,此時可以考慮使用多線程,每個線程解析一個sheet里的數據,等到所有的sheet都解析完之後,程式需要提示解析完成。在這個需求中,要實現主線程等待所有線程完成s ...
  • 一,匿名函數 def add(x,y) return x+y print(add(2,3)) f=lambda x,y:x+y #匿名函數需要lambdb來指定,lambda後直接跟參數,然後是:冒號,冒號後是表達式,只能是中表達式。當要引用匿名函數的時候,要賦值給變數才可以。 print(f(1, ...
  • 一名3年工作經驗的Java程式員應該具備的技能,這可能是Java程式員們比較關心的內容。我這裡要說明一下,以下列舉的內容不是都要會的東西—-但是如果你掌握得越多,最終能得到的評價、拿到的薪水勢必也越高。 1、基本語法 這包括static、final、transient等關鍵字的作用,foreach循 ...
  • 控制器文件: HomeController.php 基本的控制器+路由 路由參數獲取+路由別名 ...
  • 二叉樹的創建與遍歷 創建 二叉樹的4種遍歷方式: 1,先中心,再左樹,再右樹 2,先左樹,再中心,再右樹 3,先左樹,再右樹,再中心 4,層級遍歷 bintree.h bintree.c bintreemain.c nodequeue.h nodequeue.c ...
  • 在程式運行過程中,如果JVM檢測出一個不可能執行的操作,就會出現運行時錯誤。 在Java中,運行時錯誤會作為異常拋出。異常就是一個對象,表示阻止正常進行程式執行的錯誤或者情況。如果異常沒有被處理,那麼程式將會非正常終止。 異常是從方法拋出的。方法的調用者可以捕獲以及處理該異常。 throw語句的執行 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...