1. 程式人生 > >ZOJ 4063 - Tournament - [遞迴][2018 ACM-ICPC Asia Qingdao Regional Problem F]

ZOJ 4063 - Tournament - [遞迴][2018 ACM-ICPC Asia Qingdao Regional Problem F]

題目連結:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4063

Input

Output

Sample Input

2
3 1
4 3

Sample Output

Impossible
2 1 4 3
3 4 1 2
4 3 2 1

 

題意:

說現在有 $n$ 個人打比賽,要你安排 $k$ 輪比賽,要求每輪每個人都參加一場比賽。

所有輪次合起來,任意一對人最多比賽一場。

且對於任意的第 $i,j$ 輪,若 $a,b$ 在第 $i$ 輪進行了一場比賽,$c,d$ 在第 $i$ 進行了一場比賽,則 $a,c$ 在第 $j$ 輪必須進行一場比賽,$b,d$ 在第 $j$ 必須進行一場比賽。

現在要你安排比賽。

 

題解:

演算法教材上有過一道題叫“迴圈賽日程表”:

把對於題目所給的 $n$,找到一個最小的 $m$ 滿足 $2^m \ge n$,然後按照上面的思路遞迴打出表格,

然後從第二行開始進行列印前 $n$ 列,如果接下來的 $k$ 行中所有的數都是在 $1 \sim n$ 裡的,說明是OK的。否則就做不到比賽 $k$ 輪。

 

AC程式碼:

#include<bits/stdc++.h>
using namespace std;
int n,k;
int mp[1030][1030];
void t(int x)
{
    
if(x==2) { mp[1][1]=1, mp[1][2]=2; mp[2][1]=2, mp[2][2]=1; return; } t(x/2); for(int i=1;i<=x/2;i++) { for(int j=1;j<=x/2;j++) { mp[i][j+x/2]=mp[i][j]+x/2; mp[i+x/2][j+x/2]=mp[i][j]; mp[i+x/2][j]=mp[i][j]+x/2
; } } } bool ok() { for(int i=2;i<=k+1;i++) { for(int j=1;j<=n;j++) { if(mp[i][j]>n) return 0; } } return 1; } int main() { int T; cin>>T; while(T--) { scanf("%d%d",&n,&k); if(n%2 || k>=n) { printf("Impossible\n"); continue; } int N=1024; while((N/2)>=n) N/=2; t(N); if(!ok()) { printf("Impossible\n"); continue; } else { for(int i=2;i<=k+1;i++) { for(int j=1;j<=n;j++) { printf("%d%c",mp[i][j],j==n?'\n':' '); } } } } }