2020牛客多校第三场 D.Points Construction Problem

链接:https://ac.nowcoder.com/acm/contest/5668/D
来源:牛客网

Imagine you have an infinite 2D plane with Cartesian coordinate system. Initially, all the integral points are painted as white. You are given two integers n, and m. Please paint exactly n integral points to black such that there are exactly m pairs of points which satisfy the following conditions:

1. The two points are colored by different colors.

2. the two points are adjacent. We call two integral points (x1,y1)(x_1, y_1)(x1,y1) and (x2,y2)(x_2, y_2)(x2,y2) being adjacent if and only if ∣x1−x2∣+∣y1−y2∣=1|x_1 - x_2| + |y_1 - y_2| = 1x1x2+y1y2=1. (|v| means the absolute value of v.)

3. The x and y coordinates of all black points are in the range [−109,109][-10^9, 10^9][109,109].

输入描述:

The first line contains one integer t (1≤t≤1031 \le t \le 10^31t103) --- the number of test cases.

The only line of each test case contains two integers n and m (1≤n≤50,1≤m≤2001 \le n \le 50, 1 \le m \le 2001n50,1m200).

输出描述:

For each test, if there exists at least one configuration to choose n points to satisfy the conditions given by statement, you should print n+1 line for this test. The first line contains one string "Yes". And the following n lines contain the coordinator of these n points which is colored as black. If there are no solution, please print one line containing only one string "No".
示例1

输入

6
5 20
1 2
1 3
1 4
1 5
3 8

输出

Yes
1 1
2 2
3 3
4 4
5 5
No
No
Yes
1 1
No
Yes
1 1
1 2
2 1

说明

In the first test and fourth test, each black point in the sample output is adjacent to exactly 4 white points.
In the sixth test, the second and third black points in the sample output are both adjacent to 3 white points and the forst black point is adjacent to 2 white points.
 题目描述:
  在一个无限的平面上,全部点都是白色,要求给n个点染成黑色,相邻的黑白点可以配成一对,问有没有一种构造方法使配对数刚好为m。
思路:
  假设每个黑点互相独立,那么每个点对答案的贡献都是4。当黑点与黑点相邻,相当于2个相邻的黑点间连了一条边,这条边使答案贡献减2。所以可以转换成用黑点相连构造需要的边数e=(4*n-m)/2。
  显然,当4*n<m或者(4*n-m)是奇数时无答案。
  考虑最贪心的方法,试着用最少的点构造最多的边。
  1.如果e<4,直接一条链就好。e=n-1;
  2.如果e>4,先拿4个点围成一个正方形,得到4条边,
  然后考虑在矩形上加点,每行第一个加的点得到一条边,其他都是得到2条边。(列也是如此)
  所以暴力在矩阵上方和右边加点,(如下是在矩阵上方加点)因为正方形利用的点最多,所以尽量让他往正方形方向发展。
      e+1   .      e+2   ..    e+2    ...
...   ->    ...    ->    ...   ->     ...
...         ...          ...          ...

  注意一下可能存在如下的矩阵,边数为奇数的时候,在代码中加一句特判就好,具体看代码。

.
.
... ...

代码:

//#include<bits/stdc++.h>
//#include<ext/rope>
//#include<hash_map>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#define sd(x) scanf("%d",&x)
#define lsd(x) scanf("%lld",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
using namespace std;
using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> P;
const int N=1e4+99;
const ll mod=2147493647;
const int INF=1e9+7;
int s[50],n,m;
vector<P> ans;
P st;
void work(int del)
{
    if(del==0) return;
    if(del<4) 
    {
        fu(i,1,del+1) ans.push_back(st),st.first++;
        n-=del+1;
        return;
    }
    else
    {
        int pos=1;
        P now=st;
        ans.push_back(now);n--;
        while(del>0)
        {
            now.first=pos;
            now.second=0;
            del--;ans.push_back(now);
            n--;
            while(del>=2&&now.second+1<pos)
            {
                now.second++;
                del-=2;ans.push_back(now);
                n--;
            }
            if(del==0) return;
            now.first=0;
            now.second=pos;
            del--;ans.push_back(now);
            n--;
            while(del>=2&&now.first+1<pos)
            {
                now.first++;
                del-=2;ans.push_back(now);
                n--;
            }
            if(del==1) 
            {
                //特判剩下只要加一条边的情况
                del--;ans.push_back(P(pos+1,0));n--;
                return;
            }
            if(del==0) return;
            del-=2;ans.push_back(P(pos,pos));//加上这个点,构造的矩形就变成正方形
            n--;
            pos++;
        }
    }
}
int main() 
{
    //freopen("t.txt","r",stdin);
    int t;sd(t);
    while(t--)
    {
        ans.clear();
        sd(n);sd(m);
        st=P(0,0);
        if(m>4*n) puts("No");
        else
        {
            int del=4*n-m;
            if(del&1) puts("No");
            else
            {
                work(del/2);
                if(n<0) puts("No");
                else
                {
                    for(int i=1;i<=n;i++)
                    ans.push_back(P(-2,i<<1));//剩下每个点单独输出
                    puts("Yes");
                    if(!ans.empty())
                    for(P x:ans)
                    {
                        printf("%d %d\n",x.first,x.second);
                    }
                }
            }
        }
    }
    return 0;
}

 

posted on 2020-12-09 22:04  Aminers  阅读(91)  评论(0)    收藏  举报

导航