1325:【例7.4】 循環比賽日程表
時間限制: 1000 ms 內存限制: 65536 KB
提交數: 1717 通過數: 901
【題目描述】
設有NN個選手進行循環比賽,其中N=2^M,要求每名選手要與其他N−1N−1名選手都賽一次,每名選手每天比賽一次,循環賽共進行N−1N−1天,要求每天沒有選手輪空。
【輸入】
輸入:M。
【輸出】
輸出:表格形式的比賽安排表。一行各數據間用一個空格隔開。
【輸入樣例】
3
【輸出樣例】
1 2 3 4 5 6 7 8 2 1 4 3 6 5 8 7 3 4 1 2 7 8 5 6 4 3 2 1 8 7 6 5 5 6 7 8 1 2 3 4 6 5 8 7 2 1 4 3 7 8 5 6 3 4 1 2 8 7 6 5 4 3 2 1
例題不怎么詳的解:
解題時的我:
這題乍一看挺簡單的,拿着題目想了5分鍾就可以得出大致思路,我一開始想到了其實就想到了找規律,但是雖然找到了規律,卻不敢下手去碼,因為是新的一章。於是我先把這個思路放了放,轉向另一種思路。
想到了純模擬,用各種數組記錄安排啊什么的,發現這種辦法實在太麻煩,而且極其容易超時,根本不是辦法。
最后看了下書上的算法分析,恍然大悟,原來真nm是找規律,於是乎我又回到了剛開始的思路。
從題目所給的例子,眼尖的童鞋一眼就會發現左斜着的一排全是1,右斜着的一排全是8。如果有接觸過鄰接鏈表,你就會驚訝地發現這也是一個具有對稱性的表格啊!?
繼續觀察,果不其然,發現對角對稱性,即左上的部分和右下的部分完全一致,右上和左下的部分完全一致。完全一致啊!!!
深入這道題目本身的設定,原來是因為比賽的場次都會兩兩相對地重復。1和2打的要記錄,2和1打的也要記錄。
那么接下來就好辦事了,這樣一把題目分析,就找到了運用分治算法解題的思路,就是從左上角開始,用一個遞推將整個表計算出來。
算法分析:
首先是設置遞推邊界,即將模擬數組左上角的第一個數為1,然后遞推構造左上角,將左上角乘以2再復制到右上角,最后分別構造左下和右下。
得到遞推式:
以a為模擬數組,設置一個half變量來記錄所需復制的表格塊的大小(此處為關鍵點);
構造右上角:a[i][j+half]=a[i][j]+half;
構造左下角:a[i+half][j]=a[i][j+half];
構造右下角:a[i+half][j+half]=a[i][j];
由於是復制左上和右上角的數據,所以構造右上角要寫在前面。
顯而易見,總共需要構造的輪數恰好是2的指數級別,也就是說每多構造一次表格的長和寬都會乘以2。
因此,我們的主體循環結構只用循環M次。
為了再每個循環中構造新的部分,我們必須設置一個關鍵變量half來控制每次增加的表格塊,每次循環乘以2,對應表格的大小。
得到如下核心代碼:
a[0][0]=1; while(k<=m) { for(int i=0;i<half;i++) for(int j=0;j<half;j++) a[i][j+half]=a[i][j]+half;//構造右上角 for(int i=0;i<half;i++) for(int j=0;j<half;j++) { a[i+half][j]=a[i][j+half];//構造左下角 a[i+half][j+half]=a[i][j];//構造右下角 } half*=2; k++; }
有一個騷操作我必須要講,因為某個二進制位每向左移一位,相應的十進制數就會增大2倍!這個操作可以極大地優化代碼的時間復雜度,省去了用循環求2的n次方步驟。
樣例代碼:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<string> #define INF 999999999 #define N 1001 #define MOD 1000000007 using namespace std; int a[N][N]; int main() { int m; int k=1,half=1; cin>>m; int n=1<<m; a[0][0]=1; while(k<=m) { for(int i=0;i<half;i++) for(int j=0;j<half;j++) a[i][j+half]=a[i][j]+half; for(int i=0;i<half;i++) for(int j=0;j<half;j++) { a[i+half][j]=a[i][j+half]; a[i+half][j+half]=a[i][j]; } half*=2; k++; } for(int i=0;i<n;i++) { for(int j=0;j<n;j++) printf("%d ",a[i][j]); cout<<endl; } return 0; }
2019-02-12 13:41:52