CF550D题解
题意
题意翻译给的很清楚了,但是在翻译中没有提到输出格式第一行要输出点数和边数。
前置
首先题目要求存在一个桥。
那我们首先得知道什么是桥?
在上面的图中,若我们将 $2$ 和 $3$ 之间的边去掉,那么 ${0,1,2,4,5}$ 和 $3$ 将会构成两个连通块,所以 $2$ 和 $3$ 之间的边就是一个桥。
思路
在前面我们提到了桥的概念,在本题中,要求存在一个桥,那么考虑做一个轴对称,先考虑桥一边的半张图。
这是一个桥。
由于题目要求每个点的度数(连的边的数量)为 $k$,现在点 $1$ 已经连着一个桥了,那么还需要为它连上 $k-1$ 个点,以 $k=3$ 为例。
然而我们又发现 $3,4$ 的度数又为 $1$ 了,怎么办?连成一棵二叉树?
显然不现实。
那么我们加上几个辅助点试一试?那加几个呢?加一个试试?
那这个辅助点的度数又为 $2$,不可行。
那么两个呢?
每个点的度数都为 $3$,可以了!我们构造出了一组 $k=3$ 的解(的一半)。
但这只是 $k=3$ 的特例,那么 $k=5$ 的情况呢?
可以发现,$3,4,5,6$ 的度数为 $3$,那要再加点吗?
只需要两个点就够了!
显然,对于位于中间的 $3,4,5,6$ 来说,它们还需要 $k-2-1=k-3$ 条边,而中间点一共有 $k-1$ 个,除去自己还有 $k-1-1=k-2$ 个,而 $k-2>k-3$,所以只需要在中间点之间连上边就可以满足条件了。
同时,值得注意的是,为了满足条件,$k-1$ 个点至少要两两配对,所以 $k-1$ 为偶数,则 $k$ 只能是奇数。
由于上述中有 $k-2$,所以 $k=1$ 需要特判。
但在输出中要计算点数和边数,这个又怎么算呢?
每一边都有 $2$ 个辅助点, $k-1$ 个中间点,$1$ 个桥的端点,一共 $k-1+2+1=k+2$ 个点,则全图一共有 $(k+2)\times 2$ 个点。
每个点度数都为 $k$,则全图度数为 $(k+2)\times 2\times k$,每条边对度数的贡献是 $2$,则全图边数为 $\frac{(k+2)\times 2\times k}{2}=k\times(k+2)$。
代码
#include<bits/stdc++.h>
using namespace std;
int k;
int du[505];//记录度数
int main(){
scanf("%d",&k);
if(k==1)return printf("YES\n2 1\n1 2"),0;//特判
if(k%2==0)return puts("NO"),0;//不成立
int k1=k-1;//计算半边的中间点数
puts("YES");
printf("%d %d\n",2*(k+2),(k+2)*k);//计算点数和边数
for(int i=1;i<=2*(k+2);i++)du[i]=3;
for(int b=0;b<=1;b++){
for(int i=1;i<=k1;i++){
printf("%d %d\n",i+(k1+3)*b,(b+1)*(k1+3)-2);//连接辅助点一
printf("%d %d\n",i+(k1+3)*b,(b+1)*(k1+3)-1);//连接辅助点二
printf("%d %d\n",i+(k1+3)*b,(b+1)*(k1+3));//连接桥
for(int j=i+1;j<=k1&&du[i+(k1+3)*b]<k;j++){
if((i%2==0||j!=i+1)&&j!=i&&du[j+(k1+3)*b]<k)printf("%d %d\n",i+(k1+3)*b,j+(k1+3)*b),du[i+(k1+3)*b]++,du[j+(k1+3)*b]++;//连接其它中间点
}
}
printf("%d %d\n",(b+1)*(k1+3)-2,(b+1)*(k1+3)-1);//为辅助点连边
}
printf("%d %d",k1+3,2*k1+6);//连接桥
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现