SOJ 2868: find the smallest number
Description
现在我们手里有一张2维的正整数(包括0)表.
对于第i行第j列的那个数我们有如下定义:
a[i][j]是 a[i][k]{其中0<=k<j}和a[k][j]{其中0<=k<i}没有出现的那个最小的正整数
比如a[0][0]=0;
Input
有多组测试数据
每组数据一行,包括两个数:x,y,{x,y都是int型的正整数(包括0)}.
Output
输出每行一个整数, 即要找的这个数a[x][y].
Sample Input
0 0
0 1
1 0
1 1
Sample Output
0
1
1
0
Author
fgjlwj
递归分治算法 -循环赛程表
PS:第一次用学着数据结构与算法上的循环赛日程表,用二维矩阵打表,不过显然的MLE,后来自己画画图找找规律。于是就搞定了。
因为是以2次方的增长,每次递归数据规模就/2,所以int型的数据不用几次也可以求得答案。
循环赛日程表
设有n=2^k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表。
(1)每个选手必须与其他n-1个选手各赛一次。
(2)每个选手一天只能赛一次。
(3)循环赛一共进行n-1天。
按此要求可将比赛日程表设计成有n行和n-1列的表。在表中第i行和第j列处填入第i个选手在第j天所遇到的选手。
按分治测率,可以将所有选手对分成两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归的用这种一分为二的策略对选手进行分割,知道只剩下两个选手时,比赛日程表的指定就变得很简单了。这时只要让这两个选手技能型比赛就可以了。
k=1 k=2 k= 3
1 2 1 2 | 3 4 .........对称关系
2 1 2 1 | 4 3
3 4 | 1 2
4 3 | 2 1
/*
Satan | 2868 | C++ (G++-3) | Accepted | 660ms | 592KB |
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
int f(int x,int y)
{
/* 递归结束条件 */
if(x==1&&y==1) return 1;
if(x==1&&y==2) return 2;
if(x==2&&y==1) return 2;
/* 判断x,y的位置 */
int temp;
int sum1 = 0,sum2 = 0;
int key;
temp = 2;
while(temp<x)
{
temp *= 2;
sum1++;
}
temp = 2;
while(temp<y)
{
temp *= 2;
sum2++;
}
/* 递归右下方 */
if(sum1==sum2)
{
key = 1<<sum1;
return f(x-key,y-key);
}
/* 递归右上方 */
else if(sum1<sum2)
{
key = 1<<sum2;
return f(x,y-key)+key;
}
/* 递归左下方 */
else
{
key = 1<<sum1;
return f(x-key,y)+key;
}
}
int main()
{
int x,y;
while(scanf("%d %d",&x,&y)==2)
{
printf("%d/n",f(x+1,y+1)-1);
}
return 0;
}