1003E. Tree Constructing(构造)

本文探讨了如何构建一个包含特定节点数、直径和度数限制的树形结构,提供了实现方法并分析了可能的解决方案。
You are given three integers n, d and k

.

Your task is to construct an undirected tree on n

vertices with diameter d and degree of each vertex at most k

, or say that it is impossible.

An undirected tree is a connected undirected graph with n1

edges.

Diameter of a tree is the maximum length of a simple path (a path in which each vertex appears at most once) between all pairs of vertices of this tree.

Degree of a vertex is the number of edges incident to this vertex (i.e. for a vertex u

it is the number of edges (u,v) that belong to the tree, where v

is any other vertex of a tree).

Input

The first line of the input contains three integers n

, d and k (1n,d,k4105

).

Output

If there is no tree satisfying the conditions above, print only one word "NO" (without quotes).

Otherwise in the first line print "YES" (without quotes), and then print n1

lines describing edges of a tree satisfying the conditions above. Vertices of the tree must be numbered from 1 to n

. You can print edges and vertices connected by an edge in any order. If there are multiple answers, print any of them.1

Examples
Input
Copy
6 3 3
Output
Copy
YES
3 1
4 1
1 2
5 2
2 6
Input
Copy
6 2 3
Output
Copy
NO
Input
Copy
10 4 3
Output
Copy
YES
2 9
2 10
10 3
3 1
6 10
8 2
4 3
5 6
6 7
Input
Copy
8 5 3
Output
Copy
YES
2 5
7 2
3 7
3 1
1 6
8 7
4 3

题意

让你构造一个节点数为n,直径为d,且所有点的度数均小于k的树。

题解

我们先用1~(n+1)把直径做出来,然后用dfs去添加其他结点,我们可以在第i个结点去挂上一棵深度不超过min(i-1,d-i+1)的树,注意在生成这棵树的时候每个结点的度数不能超过k。总结点数==n时,及时结束。

那么什么时候无解呢,①节点数小于等于直径(这样直径都搞不出来),②直径>1且每个点的度数不能超过2,③n个结点没有全部挂上去。

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
int n,d,k;
int id;
vector< pair<int,int> >ans;
void DFS(int u,int dep,int maxd){
	if(dep==maxd) return;
	for(int i=0;i<k-1-(dep==0) && id<n;i++){
		ans.push_back(make_pair(u,++id));
		DFS(id,dep+1,maxd);
	}
}
int main(){
	cin>>n>>d>>k;
	if(n<=d||d>1&&k<2){
		cout<<"NO"<<endl;
		return 0;
	}
	for(int i=1;i<=d;i++)
	   ans.push_back(make_pair(i,i+1));
	id=d+1;
	for(int i=2;i<=d;i++) DFS(i,0,min(i-1,d-i+1));
	if(id<n) cout<<"NO"<<endl;
	else{
		cout<<"YES"<<endl;
		for(int i=0;i<ans.size();i++)
		   cout<<ans[i].first<<" "<<ans[i].second<<endl;
	}
	return 0;
}

根据题目描述,需要我们设计一个类来模拟对象的构造和析构过程,并按照指定规则生成对应的输出。下面详细介绍如何实现这一功能。 --- ### **解题思路** 1. 设计一个简单的类 `Object` 来表示每个对象的行为。 - 在该类中包含两个方法:构造函数 (`Constructor`) 和析构函数 (`Destructor`)- 构造函数会打印类似 `Constructing object X` 的消息,其中 `X` 是当前对象编号。 - 析构函数会在对象销毁时打印类似 `Destructing object X` 的消息。 2. 主函数需按以下逻辑运行: - 从标准输入读取两部分内容: - 测试数据组数 `t`。 - 每一组的对象个数 `ni`(每组单独处理)。 - 创建相应数量的对象实例并让它们依次构造、析构。 3. 输出结果应完全匹配样例中的格式。 --- ### **代码实现** 以下是 C++ 的完整代码: ```cpp #include <iostream> using namespace std; // 定义 Object 类 class Object { private: int id; // 存储对象编号 public: // 构造函数 explicit Object(int objectId) : id(objectId) { cout << "Constructing object " << id << endl; } // 析构函数 ~Object() { cout << "Destructing object " << id << endl; } }; int main() { ios::sync_with_stdio(false); // 加速 I/O cin.tie(nullptr); int t; // 输入测试数据的组数 cin >> t; while (t--) { // 循环处理每一组 int n; // 当前组的对象个数 cin >> n; for (int i = 1; i <= n; ++i) { // 使用作用域控制对象生命周期 { Object obj(i); // 构造第 i 个对象 } // 离开作用域后立即触发析构函数 } } return 0; } ``` --- ### **代码解析** 1. **类定义** - 我们通过 `explicit Object(int objectId)` 显式声明了一个带参数的构造函数。 - 成员变量 `id` 记录了当前对象的唯一标识符。 - 析构函数 `~Object()` 自动在对象超出其作用范围时调用。 2. **主函数逻辑** - 首先读取总的测试组数 `t`。 - 对于每一组测试数据: - 先读取当前组的对象个数 `n`。 - 再循环创建每一个对象,同时利用大括号 `{}` 将每个对象的作用域限定在一个小范围内。 - 这样可以确保每次迭代结束后都会自动调用析构函数。 3. **性能优化** - 添加了 `ios::sync_with_stdio(false);` 和 `cin.tie(nullptr);` 来提升程序的输入/输出效率。 --- ### **运行示例** 假设输入为: ``` 2 3 4 ``` 程序运行时会产生如下输出: ``` Constructing object 1 Destructing object 1 Constructing object 2 Destructing object 2 Constructing object 3 Destructing object 3 Constructing object 1 Destructing object 1 Constructing object 2 Destructing object 2 Constructing object 3 Destructing object 3 Constructing object 4 Destructing object 4 ``` 这与题目要求一致。 --- ### **总结** 本题的核心在于掌握 C++ 中对象的构造与析构机制以及合理地使用作用域控制对象的生存周期。此外,注意保持良好的代码习惯(如显式声明构造函数),以增强代码的安全性和可维护性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值