2020牛客暑期多校訓練營(第三場)D Points Construction Problem 構造思維題

夕林山寸發表於2020-09-26

巧妙的思維構造題。

如果直接手畫找規律還是蠻難的。

一般這種題需要先分析一下性質,找出最優最方便的構造方法。

題目要求連線黑白的邊的數量。

顯然上界是4*n;

下面分析下界:

仔細分析可知,若黑點位於不同的r行,c列,則連線邊數量最少為:

2*(a+b),因為每一行至少存在   白(-oo)-黑  黑-白(+oo)

列同理。

所以我們只需要列舉a,b就能找出最小的下界了。

下界構造:從下往上,從左往右填色。

每次把一個點移到很遠的地方,總數量會加2或者加4.

最後如果數量超出m(一定是多了2),則只需要把移走的點移動到任意一個點的旁邊即可+2.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
vector<pair<int,int> >v,pr;
int a[210][210];
int b[310][507];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int T;
	  cin>>T;
	while(T--){
		int n,m;
		cin>>n>>m;
		int mn=4*n+1;
		if(mn<m||m&1){
			cout<<"No"<<endl;
			continue;
		}
		memset(a,0,sizeof(a));
		v.clear();
		pr.clear();
		int r=0,c=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				if(i*j>=n && 2*(i+j)<mn){
					mn=2*(i+j);
					r=i,c=j;
				}
			}
		if(mn>m){
			cout<<"No"<<endl;
			continue;
		}
		int sz=0;
		for(int i=1;i<=r;i++)
			for(int j=1;j<=c;j++)
				if(sz<n)a[i][j]=1,v.pb({i,j}),++sz;	
		int nm=0;
		while(mn<m){
			auto tp=v[v.size()-1];
			int x=tp.first,y=tp.second;
			if(a[x][y-1])mn+=2;if(a[x-1][y])mn+=2;
			if(a[x][y+1])mn+=2;if(a[x+1][y])mn+=2;
			
			a[x][y]=0;
			v.pop_back();
			pr.pb({300,2+nm*2}),nm++;
		}
		for(auto x:v)pr.pb({x.first,x.second});
		int st=0;
		if(mn>m){
			auto tp=pr[1];
			int x=tp.first,y=tp.second;
			pr.pb({x-1,y});
			st=1;
		}
		cout<<"Yes"<<endl;
		memset(b,0,sizeof(b));
		for(int i=st;i<pr.size();i++){
			auto x=pr[i];
			b[x.first][x.second]=1;
			cout<<x.first<<" "<<x.second<<endl;
		}
	/*
		檢測程式碼: 
			int ans=0;
		for(int i=0;i<=300;i++)
		for(int j=0;j<=410;j++)
		{
			if(b[i][j]){
				if(i==0||!b[i-1][j])ans++;
				if(!b[i+1][j])ans++;
				if(!b[i][j+1])ans++;
				if(j==0||!b[i][j-1])ans++;
			}
		}
		if(ans!=m){
			cout<<ans<<"  "<<"NO!!!!!!!!!!!!!!!!!!!!!!!"<<endl;
			break;
		}*/
	}
	return 0;
}
/*

11
1111
1111
1111 
*/

 

相關文章