题目大意:给定一个(2n imes 2n)的平面,在上面取(n imes n)个整点,使得任意两点之间距离( eq sqrt{D1},sqrt{D2})。
题目链接:D - Choosing Points
题解:我们先考虑只有(D1)限制的情况,我们将所有距离为(sqrt{D1})的整点连上边,会发现这是一张二分图。证明如下:
考虑将棋盘黑白染色,如果(D1)为奇数,那么黑点和黑点之间不可能连边,白点和白点之间也不可能连边,所以容易证明。
如果(D1)为偶数,黑点之间会互相连边,白点亦是如此,那么将坐标缩小为原来的(frac{1}{sqrt{2}}),然后(D1 div 2)转换为子问题。
所以按照(D1)的限制黑白染色,然后在按照(D2)的限制红蓝染色,根据染色结果将所有的分为 4 类,由于鸽巢原理,一定有至少一类的大小是大于(n imes n)的,所以直接输出即可。
代码:
#include <cstdio>
#include <cstring>
const int Maxn=600;
const int D[4][2]={{1,1},{1,-1},{-1,1},{-1,-1}};
int n,d[2];
int step[2][2][Maxn*Maxn+5];
int len[2];
int num[5];
int col[2][Maxn+5][Maxn+5];
void dfs(int k,int x,int y,int c){
if(x<1||y<1||x>n||y>n||col[k][x][y]!=-1){
return;
}
col[k][x][y]=c;
for(int i=1;i<=len[k];i++){
for(int j=0;j<4;j++){
dfs(k,x+D[j][0]*step[k][0][i],y+D[j][1]*step[k][1][i],c^1);
}
}
}
int main(){
scanf("%d%d%d",&n,&d[0],&d[1]);
n<<=1;
for(int k=0;k<2;k++){
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
if(i*i+j*j==d[k]){
step[k][0][++len[k]]=i;
step[k][1][len[k]]=j;
}
}
}
}
memset(col,-1,sizeof col);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dfs(0,i,j,0);
dfs(1,i,j,0);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
num[col[1][i][j]<<1|col[0][i][j]]++;
}
}
int tmp;
for(int i=0;i<4;i++){
if(num[i]>=(n*n>>2)){
tmp=i;
}
}
int sz=0;
for(int i=1;i<=n&&(sz<(n*n>>2));i++){
for(int j=1;j<=n&&(sz<(n*n>>2));j++){
if((col[1][i][j]<<1|col[0][i][j])==tmp){
sz++;
printf("%d %d
",i-1,j-1);
}
}
}
return 0;
}