注意到棋盘可以看成无限大的,那么只要考虑如何构造一个尽可能合法的情况
不妨假设需要的白色格子比黑色格子少
那么容易发现最好的情况之一就是白色排一排然后中间黑的先连起来,剩下黑色的再全部填白色周围
可以证明如果需要 $w$ 个白色格子,那么黑色格子的数量不能超过 $3w+1$
证明:首先 $w=1$ 时显然
然后考虑下一个白色格子扩展,显然从一边延伸出去,然后又多了 $3$ 个可以放黑色的位置,这样一路扩展显然可以放 $3w+1$ 个黑色的位置
然后考虑证明没有更好的方案,显然除了第一次白色可以提供四个黑色位置以外,之后放扩展白色时,至少要有其中一边和原本的黑色相邻,那么每次扩展多就只能多 $3$ 个合法位置
证明完毕
然后直接按构造的搞就行了,注意一下细节就行
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int Q,b,w; inline bool pd(int x,int y) { return (x+y)&1; } int main() { Q=read(); while(Q--) { b=read(),w=read(); if(b>3*w+1||w>3*b+1) { printf("NO\n"); continue; } printf("YES\n"); int px,py,l; if(w>=b) px=py=2; else px=2,py=3; l=py; while(w||b) { if(pd(px,py)) { if(!b) { py--; break; } b--; } else { if(!w) { py--; break; } w--; } printf("%d %d\n",px,py); py++; } for(int i=l;i<=py;i++) { if(pd(px,i)&&w) { printf("%d %d\n",px-1,i); w--; if(w) printf("%d %d\n",px+1,i),w--; } if((!pd(px,i))&&b) { printf("%d %d\n",px-1,i); b--; if(b) printf("%d %d\n",px+1,i),b--; } } if(b||w) printf("%d %d\n",px,py+1); } return 0; }