Codeforces Round 793 (Div. 2)D. Circular Spanning Tree(图论,思维,构造)

题目链接:https://codeforces.com/contest/1682/problem/D

 

题意:

 

给n个点,围成一个圈,你可以添加 n - 1条边使他成为一棵树,限制条件如下:

 

1:给长度为n的字符串,字符集为 0 和 1,对于 第i个字符,如果是1,表示第i个点的度数为奇数,反之为偶数;

 

2:边不能相交;

 

现在让你给出构造方案,如果不能构造,输出“NO”

 

分析:

 

我们分析,什么时候这棵树一定可以构造出来;

 

1:树都是有叶子的,故没有奇数的就 一定不行;

 

2:考虑一棵树是由一条条线段组成,一开始,一条线段有俩个奇数;

 

如果俩条线段是端点相连,那么结果还是俩个奇数;

 

如果一条线段连在另一线段中间,那么会变成4个奇数;

 

综上:如果没有奇数  或  奇数的个数是奇数个,那么无解;

 

现在我们来构造:

 

如果全部都是1,那么我们把n - 1个点连到第一个点上即可;

 

否则一定会有一个0,我们选取1相邻的一个0:

 

对于每个1,我们以他为头,依次把后面的0串起来,到最后一个0 的时候,我们把那个0的下一端连到上面我们选取那个0 那里,因为会有偶数个1,所以会有偶数个线段和0相连,是符合条件的;

 

时间复杂度:O(n)

 

代码:

 

#include<bits/stdc++.h> int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); int T; std::cin >> T; while (T--) { int n; std::cin >> n; std::string s; std::cin >> s;s += s[0]; int cnt = 0; for (int i = 0; i < n; ++i)cnt += (s[i] - '0'); if (!cnt || cnt % 2) { std::cout << "NO\n"; continue; } std::vector<std::pair<int, int>>ans; int st = 0; for (int i = 0; i < n; ++i)if (s[i] == '0' && s[i + 1] == '1') { st = i; break; } for (int i = (st + 1) % n; i != st; i = (i+1)%n) { int mid = (i + 1) % n; while (s[mid] == '0')ans.push_back(std::make_pair((mid - 1 + n) % n + 1, mid + 1)), mid = (mid + 1) % n; mid = (mid - 1 + n) % n; if (mid == st)break; else ans.push_back(std::make_pair(mid + 1, st + 1)); i = mid; } std::cout << "YES\n"; for (auto& [x, y] : ans)std::cout << x << " " << y << "\n"; } return 0; }

哈哈哈,妙妙构造:)


__EOF__

本文作者XiCen
本文链接https://www.cnblogs.com/ACMER-XiCen/p/17662824.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   XiCen  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示