题目链接: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 "); continue; } int N=1024; while((N/2)>=n) N/=2; t(N); if(!ok()) { printf("Impossible "); 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?' ':' '); } } } } }