① 问题描述
设有n=2^k个运动员,要进行网球循环赛。现在要设计一个满足以下要求的比赛日程表
(1).每个选手必须与其他n-1个选手各赛一场
(2).每个选手一天只能赛一次
(3).循环赛一共进行n-1天。
② 这种表只有一种情况。可以用经典的分治来做。
发现 当表的长度为4时,存在
1 2 3 4
2 1 4 3
3 4 1 2
当n为8时
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
所以我们可以递归的处理。(递推也是可以得。)
还有一种基于小范围的写法。
我后来发现这个表就是 输出当前行当前列没出现的最小的数就行了。
于是能不能进行暴力的输出呢。
压位 ,判断当前行当前列是否存在这个数。
(由于压位的时候,是用int,所以只能处理32位。最多64)
比方说 ,0表示当前位的数尚未出现,1表示当前位的数已经出现了。
用lowbit 来找到最小的1.
#include <bits/stdc++.h>
using namespace std;
const int maxn=103;
int m;
int dp[maxn][maxn];
void solve(int n){
if(n<=1)
return ;
// solve ָײײַי¿צ
//cout<<n<<endl;
solve(n/2);
if(n>2){
n/=2;
for(int i=1;i<=n;i++){
for(int j=n+1;j<=n*2;j++){
dp[i][j]=dp[i][j-n]+n;
}
}
for(int i=n+1;i<=n*2;i++){
for(int j=1;j<=n;j++)
dp[i][j]=dp[i-n][j]+n;
}
for(int i=n+1;i<=n*2;i++){
for(int j=n+1;j<=n*2;j++)
dp[i][j]=dp[i-n][j-n];
}
}
else if(n==2){
dp[1][1]=1;
dp[1][2]=2;
dp[2][1]=2;
dp[2][2]=1;
}
return ;
}
int main()
{ int n;
while(~scanf("%d",&n)){
solve(n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d ",dp[i][j]);
}
cout<<endl;
}
}
return 0;
}
用lowbit
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned in;
int m;
const int maxn=2000;
in row[maxn];
in col[maxn];
int lowbit(in x){
return x&(-x);
}
int main()
{
for(int i=0;i<maxn;i++){
col[i]=0;
row[i]=0;
}
in m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
printf("%d ",i);
col[1]|=(1<<i-1);
row[i]|=(1<<i-1);
for(int j=2;j<=m;j++){
in s=lowbit(~(col[j]|row[i]));
in ss=log2(s*2);
printf("%d ",ss);
col[j]|=(1<<ss-1);
row[i]|=(1<<ss-1);
}
cout<<endl;
}
return 0;
}