agc025_d Choosing Points

agc025_d Choosing Points

https://atcoder.jp/contests/agc025/tasks/agc025_d

UKeeHg.png

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);
}
原文地址:https://www.cnblogs.com/ljzalc1022/p/13279117.html