D.Circular Spanning Tree
D题链接
题意:给定n个点,这n个点均匀分布在一个圆上构造一棵树,现在给你一个二进制字符串s,对于s[i],当s[i]==0时代表编号为i的点入度为偶数,s[i]==1代表编号为i的点入度为奇数。现在想让这n个点通过n-1条边联通,并且任意两条边都不相交。
思路:首先我们应该思考,什么时候是不能构造出一颗树的
1.如果字符串全是0,那么我们每个点至少两个度,那边的数量最少也是n这样就符合题意,因此不行
2.1的个数必须是偶数,因为我们可以假设一下,如果是一个正常的链,那么头和尾一定是度为1,那么至少要两个,如果再多两个可以通过其他点进行链接,但如果是奇数,那么既不能单独作为头和尾,也不能用其他0号点进行连接。
判断好YN之后,我们来构造一下,边应该怎么写。
我们将那些度为1的点作为叶子节点,然后将他们串在一起(相邻的串在一起),传完之后呢,所以的1基本都分离了,那么我们有偶数个1,可以选取应该偶数节点和其他的链连上即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
int n;
string s;
cin>>n>>s;
vector<int>acm;
for(int i=0;i<n;i++)
{
if(s[i]=='1')
acm.push_back(i);
}
if(acm.size()%2!=0||acm.size()==0)
{
cout<<"NO"<<endl;
return ;
}
cout<<"YES"<<endl;
for(int i=0;i<acm.size();i++)
{
for(int j=acm[i];(j+1)%n!=acm[(i+1)%acm.size()];j++)
{
cout<<j%n+1<<" "<<(j+1)%n+1<<endl;
}
}
for(int i=1;i<acm.size();i++)
{
cout<<(acm[0]+n-1)%n+1<<" "<<acm[i]<<endl;
}
}
int main() {
int T;
cin >> T;
while (T--) {
solve();
}
}