agc025_d Choosing Points
https://atcoder.jp/contests/agc025/tasks/agc025_d
Tutorial
https://img.atcoder.jp/agc025/editorial.pdf
我们要解决的问题实际上是
有两个大小为(V)的二分图,需要找到一个大小为(dfrac V4)的点集,满足这个点集在两张图上都是独立集
首先,证明若在两个距离为(D)的点之间连一条边,那么这会形成一张二分图.
若(D)是奇数,那么若((x,y),(x+s,y+t))之间距离为(D),那么(s^2+t^2)距离为奇数,也就是说(s,t)的奇偶性不同,所以我们可以根据(x+y)的奇偶性也就是棋盘染色将其分为二分图.
若(D)是偶数,那么棋盘染色后,有连边的点一定颜色相同,不妨考虑所有黑色的点,可以旋转(45)度后将其看做一个方格图,且此时距离为(d)相当于原图上距离为(sqrt 2d) ,那么此时的(D)变为(dfrac D2).那么不断递归就会变成(D)为奇数的情况.
证毕
回到我们转化后的问题,可以对两个二分图分别黑白染色,于是每个点可以根据它在两张图上的颜色分为(4)类,根据抽屉原理,一定存在一类点数量大于等于(dfrac V4),而且根据黑白染色的定义,在同一集合中的点一定是独立集.于是就找到了答案
Code
#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define fi first
#define se second
using namespace std;
inline char gc() {
return getchar();
static char buf[100000],*l=buf,*r=buf;
return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void rd(T &x) {
x=0; int f=1,ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
x*=f;
}
const int maxn=300+5;
int n,D1,D2;
struct Solver {
int col[maxn<<1][maxn<<1];
vector< pair<int,int> > V;
void init(int D) {
for(int i=0;i<2*n;++i) for(int j=0;j<2*n;++j) {
if(i*i+j*j==D) {
V.push_back(make_pair(i,j));
V.push_back(make_pair(-i,j));
V.push_back(make_pair(i,-j));
V.push_back(make_pair(-i,-j));
}
}
}
void dfs(int x,int y,int c) {
if(col[x][y]!=-1) return;
// debug("%d %d %d
",x,y,c);
col[x][y]=c;
for(int i=0;i<V.size();++i) {
int _x=x+V[i].fi,_y=y+V[i].se;
if(_x<0||_x>=n*2) continue;
if(_y<0||_y>=n*2) continue;
dfs(_x,_y,c^1);
}
}
void sol(int D) {
init(D);
memset(col,-1,sizeof(col));
// debug("---
");
for(int i=0;i<2*n;++i) for(int j=0;j<2*n;++j) if(col[i][j]==-1) {
dfs(i,j,0);
}
}
} solver[2];
int main() {
rd(n),rd(D1),rd(D2);
solver[0].sol(D1),solver[1].sol(D2);
vector< pair<int,int> > S[4];
for(int i=0;i<2*n;++i) for(int j=0;j<2*n;++j) {
S[solver[0].col[i][j]<<1|solver[1].col[i][j]].push_back(make_pair(i,j));
}
for(int i=0;i<4;++i) if(S[i].size()>=n*n) {
for(int j=0;j<n*n;++j) printf("%d %d
",S[i][j].fi,S[i][j].se);
return 0;
}
assert(0);
}