2018AHU新生赛Panelatta与华容道题解
2018AHU新生賽Panelatta與華容道題解
題目描述
Panelatta很喜歡玩益智游戲,今天,他又開始玩一個古老的游戲:華容道!但是Panelatta不喜歡原版的華容道,所以他對此做了一些修改。給定一個由 n2n^{2}n
?2
?? ( n 為奇數)個方格組成的 n?n 方陣,在 n?n?1 個方格中填入數字 1 ~ n?n?1 ,并將剩下的一個方格留空。在游戲過程中,可以將空置的方格與其上下左右方向的任何一個數字交換。Panelatta將這個游戲稱為 n 階華容道。
現在給你兩個 n 階華容道游戲的局面,請判斷是否存在一種移動空置方格的方法,使得從其中一個局面可以變換成另一個局面?
輸入格式
多組數據,對于每組數據:
第1行一個奇數 n ,(n < 500)
接下來 n 行,每行 n 個整數,表示第一個局面。
接下來 n 行,每行 n 個整數,表示第二個局面。
每個局面中用 0 表示空置方格,并保證每個局面都恰好用數字 0 ~ n?n?1填充滿。
輸出格式
對于每組數據,若兩個局面可達,輸出TAK,否則輸出NIE。
樣例
輸入樣例
3
1 2 3
0 4 6
7 5 8
1 2 3
4 5 6
7 8 0
1
0
0
輸出樣例
TAK
TAK
注:xls出的這個題沒點相關知識的話太難了,不愧是AHU全能王,出題就是有水平 ?
下面先介紹這道題所涉及到的相關知識點:
奇排列
下面是百度百科上對奇排列 先自行閱讀后再看下面的解釋
https://baike.baidu.com/item/奇排列/18881587?fr=aladdin
看完百度百科對奇排列的解釋后 不難知道以下結論:
定理1 : 對換改變排列的奇偶性。(經過一次對換,奇排列變成偶排列,偶排列變成奇排列。
例如:1 2 3 4 5 6是逆序對為0 所以為偶排列 若調換其中任意兩個位置的數 比如1 5 3 4 2 6 就變成偶排列
定理2 :任意一個n級排列與排列 都可以經過一系列對換互變,并且所作對換的個數與這個排列有相同的奇偶性。
定理2結合定理1也不難理解,偶排列換一次變成奇排列,再變化一次就變成了偶排列,以此類推得知:互變的次數的奇偶性與排列的奇偶性保持一致。
那么華容道是怎樣具有排列的性質呢?
首先理解華容道不一定總是有解的,比如網上很火的一道數字華容道題
具體可以看下這個有關華容道里群論的視頻:華容道群論視頻
這種數字華容道是無解的,而原因就是因為它是一種奇排列,而他要變成的1 2 3 4…… 14 15是一種偶排列,我們不難想到奇排列與偶排列在數字華容道中不能互相轉化。
了解了上面的知識再來看這道題 給出兩個數字華容道 問第一個能否轉換成第二個,換個思路想,問題可以轉化為第一個第二個是否都是同一種排列(比如都是奇排列和偶排列)。轉化為這個問題后,我們又要想到如何判斷數字華容道的排列的奇偶性,那不妨找一個標準排列來與這兩個數字華容道作比較,看看這兩個數字華容道要互換幾次才能變成我們所規定的那個標準排列,若兩種變化次數為奇數或偶數,說明這兩種排列具有相同的奇偶性,故可以相互轉化,輸出TAK。
不妨令標準排列為1 2 3 4 5 6 7 ……
此時問題就轉化為了一個排列最少交換幾次才能變成1 2 3 4 5 6 7……這種升序排序。
由于數據為500*500=250000 數據很大 冒泡排序等方法很容易被卡超時
下面介紹一種復雜度o(n)的方法來處理這種問題:
創建一個數組記錄一組數 然后再創建一個數組來記錄數所對應的位數 比如第一組數 1 2 3 4 6 7 5 8 第一個數組叫a[1]=1 a[2]=2…a[5]=6 a[6]=7 a[7]=5 然另一個數組arem[1]=1 arem[2]=2 arem[6]=5 arem[7]=6 arem[5]=7 然后遍歷 如果a[i] ! =i 就讓arem[i]查到i值在第幾位 然后讓a[i]與a[arem[i]]交換數值 同時更新arem數組
注:更新arem數組的作用何在?
如果交換完位置后還用原來的數值記錄位置就會在后面調取某個數值的位置時產生錯誤。
ac代碼
幸運的是這道題內存限制沒什么要求,但是我們可以進一步優化下內存,我們可以讓a和arem數組輸入完成后直接進入運算cnta的奇偶性,然后再把原來的b和brem直接輸入到a和arem,這樣就省去了b和brem所占有的內存。
下面是改進版本的代碼:
// An highlighted block #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; int a[250000],arem[250000]; int main() {//freopen("1.in","r",stdin);int t=10;while(t--){int n,cnta=0,cntb=0,tep;int m,q;scanf("%d",&n);if(n==0){continue;};if(n==1){scanf("%d",&n);scanf("%d",&n);printf("TAK\n");continue;}for(int i=1;i<=n*n-1;i++){scanf("%d",&a[i]);if(a[i]==0){i=i-1;continue;}arem[a[i]]=i;}for(int i=1;i<=n*n-1;i++){if(a[i]!=i){m=arem[i];q=a[i];tep=a[arem[i]];a[arem[i]]=a[i];a[i]=tep;cnta++;arem[q]=m;}}for(int i=1;i<=n*n-1;i++){scanf("%d",&a[i]);if(a[i]==0){i=i-1;continue;}arem[a[i]]=i;}for(int i=1;i<=n*n-1;i++){if(a[i]!=i){m=arem[i];q=a[i];tep=a[arem[i]];a[arem[i]]=a[i];a[i]=tep;cntb++;arem[q]=m;}}if(cnta%2==cntb%2){printf("TAK\n");}else{printf("NIE\n");}}return 0; }內存少了一半左右,且排序算法是o(n)的,現在應該是優化的很好的代碼啦。
下面再貼一種出題人Xls滴方法。
xls滴排序是o(nlogn)的方法。
// An highlighted block #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int maxn=5e5+5;long long ans; int a[maxn]; int r[maxn];void msort(int s,int t){if(s==t)return;int mid=(s+t)/2;msort(s,mid);msort(mid+1,t);int i=s,j=mid+1,k=s;while(i<=mid&&j<=t){if(a[i]<=a[j]){r[k]=a[i];k++;i++;}else{r[k]=a[j];k++;j++;ans+=mid-i+1;}}while(i<=mid){r[k]=a[i];k++;i++;}while(j<=t){r[k]=a[j];k++;j++;}for(int i=s;i<=t;i++)a[i]=r[i]; } int main(){int n;int p;int val;while(~scanf("%d",&n)){p=1;for(int i=1;i<=n*n;i++){scanf("%d",&val);if(val!=0){a[p]=val;p++;}}ans=0;msort(1,p);long long t=ans;p=1;for(int i=1;i<=n*n;i++){scanf("%d",&val);if(val!=0){a[p]=val;p++;}}ans=0;msort(1,p);if(t%2==ans%2)printf("TAK\n");else printf("NIE\n");}return 0; }問題到此就解決了?
最后表白郭希賢同學!!!!
總結
以上是生活随笔為你收集整理的2018AHU新生赛Panelatta与华容道题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring boot 整合 云之讯 d
- 下一篇: SPI、I2C、UART的区别和联系