時間限制: 1000 ms 記憶體限制: 65536 kb
提交數: 1717 通過數: 901
設有n'>n
n個選手進行迴圈比賽,其中n=2
m'>2^m
,要求每名選手要與其他n−1
'>n−1
n−1名選手都賽一次,每名選手每天比賽一次,迴圈賽共進行n−1
'>n−1
n−1天,要求每天沒有選手輪空。
輸入:m
'>m
。輸出:**形式的比賽安排表。一行各資料間用乙個空格隔開。
3
1 2 3 4 5 6 7 82 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有乙個騷操作我必須要講,因為某個二進位制位每向左移一位,相應的十進位制數就會增大2倍!這個操作可以極大地優化**的時間複雜度,省去了用迴圈求2的n次方步驟。
樣例**:
#include#include#include#include#include#include#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<2019-02-12 13:41:52
迴圈比賽日程表
總時間限制 1000ms 記憶體限制 65535kb 描述 設有n個選手進行迴圈比賽,其中n 2 m,要求每名選手要與其他n 1名選手都賽一次,每名選手每天比賽一次,迴圈賽共進行n 1天,要求每天沒有選手輪空。輸入m m 10 輸出 形式的比賽安排表 數字之間以乙個空格分開 樣例輸入 3 樣例輸出 ...
迴圈比賽日程表
設有n個選手進行迴圈比賽,其中n 2m,要求每名選手要與其他n 1名選手都賽一次,每名選手每天比賽一次,迴圈賽共進行n 1天,要求每天沒有選手輪空。輸入正整數m。形式輸出比賽安排表。整數之間用空格隔開,詳見樣例 第一行輸出n個數,表示選手的編號。後面緊接n 1行,每行表示一天的比賽安排。1 2 3 ...
分治 1325 迴圈比賽日程表
今天做了一道題 迴圈比賽日程表,這是一道分治的題,並不太難,看看樣例就懂了。首先,我們以 中心拆分,把 分成四個部分 如上圖所示 你就會驚奇的發現。坐上和右下的部分完全一樣,左下和右上的部分也完全一樣,並且繼續查分的話,這個規律同樣適用。這個時候,你可能已經有思路了。下面,源 1 include2 ...