Codeforces Round #793 D. Circular Spanning Tree(构造)

思路:首先讨论点的度数,整个点的度数应该都是偶数的(每条边贡献两度),那就意味这奇数点的个数是偶数

所以奇数点的个数是奇数的直接输出NO

接下来则讨论如何构造不存在交叉边的图

对于这样一个图

 

 要构造所有边都尽量不相邻的方法是

 

 即一个类似树的结构,我们很自然会想到构建一个树

为了保证偶数点的的度为偶数,我们可以将它们串联成一条链,链尾是奇数点(即叶子节点)

之后则是随机找一个偶数点作为树的顶点

链条个数取决于奇数点个数,所以保证顶点度数不会被改变

AC代码:

#pragma GCC optimize(2)
#pragma GCC optimize(1)
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
const ull base=131;
#define MAX 1009
#define PI 3.141592653589793
using namespace std;
inline void solve(){
    int len;
    string op;
    cin>>len>>op;op=" "+op;
    int c=0;
    for(int i=1;i<=len;i++) if(op[i]=='1')c++;
    if(c%2||c<2){
        cout<<"No"<<"\n";return;
    }
    cout<<"Yes\n";
    vector<pair<int,int>> edge;//存边
    vector<int> lank[len+3];
    int beg=1;
    int num=1,time=0;
    for(;beg<=len;beg++) if(op[beg]=='1')break;//记录第一个1的位置
    while(1){
        while(1){
            lank[num].push_back(beg);
            if(beg<len) beg++;
            else beg=1;
            time++;
            if(op[beg]=='1'||time==len) break;
        }
        reverse(lank[num].begin(), lank[num].end());
        if(time==len) {
            break;
        }
        num++;
    }
    int txt=lank[num][0];
    for(int i=1;i<num;i++){
        edge.push_back({lank[i][0],txt});
    }
    for(int i=1;i<=num;i++){
        int si=lank[i].size();
        for(int j=0;j<si-1;j++){
            edge.push_back({lank[i][j],lank[i][j+1]});
        }
    }
    int all=edge.size();
    for(int i=0;i<all;i++) cout<<edge[i].first<<' '<<edge[i].second<<"\n";
   
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int sum;cin>>sum;
    while(sum--){
        solve();
    }
}

 

posted on 2022-05-24 19:59  zesure  阅读(38)  评论(0编辑  收藏  举报

导航