1. 程式人生 > 實用技巧 >2020牛客多校第三場 D.Points Construction Problem

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 sixthtest, 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;
}