发觉自己水平越来越烂真是一件悲伤的事。。
要好好加油了
题意
给定一个k(1<=k<=100),要求求出一张无向图,这张无向图的每个顶点度数都是k(有k条边和这个顶点相连),而且无向图至少要有一个桥(求出的无向图只能有一个连通块)。
割顶/关节点:在连通图中,去掉一个顶点,能让这张图不再全连通(变成两个连通块)。
桥:在连通图中,去掉一条边,能让这张图不再全连通(变成两个连通块)。
思路
下面我们来考虑图中只有一个桥的情况(好吧只需要考虑这个)。
我们可以想当然的认为构造出来的图是这样的:假设我们的图中一共有2n+4(为什么这样一会儿会解释)个顶点,则每边的顶点个数应该为n+2,同时每一侧有一个顶点和另外一侧相连(形成桥),因此构造的图可以是对称的,只要考虑一边就好了。
图的总度数为(2n+4)*k,总边数(也相当于一侧的度数)为(n+2)*k。
若不考虑中间相连的边,则左侧的度数为(n+2)*k-1。
1.当k为偶数时, (n+2)*k-1,一定是奇数,而一个连通图不可能度数为奇数,因此k为偶数时全部是NO。
2.下面考虑k为奇数的情况,由于每个顶点的度数要求为k,所以该顶点必须和k个顶点相连,考虑单独一侧,则该侧至少要k+1个顶点。但是如果一侧只有(k+1)个顶点,那么(k+1)*k-1依然是奇数,所以至少要有(k+2)个顶点(当然k+4也是可以的)。
确定了每边的顶点数后,下面我们来考虑如何构造。
意淫过程参考自:http://blog.youkuaiyun.com/codebattle/article/details/46383049
首先,1号顶点(桥的一侧)需要和k-1个顶点相连,此时这k-1个顶点每个还差k-1度,我们让他们互相连接,此时这k-1个顶点还差1度。
引入第k+1号顶点,让他去和这k-1个顶点相连,此时前k个顶点满足条件,第k+1号顶点还差1度,因此再引入第k+2号顶点,与第k+1号相连。
此时所有顶点中,只有第k+2号还差k-1度,我们可以想办法让2-k号各下降1度,然后让他们与第k+2号相连。
由于k是奇数,因此2-k共有偶数个顶点,这些顶点是互相连接的,具体的做法可以是,删除2-3,4-5,6-7…(k-1)-(k)之间的边,这样2-k号各下降1度。
说了这么多,其实编程实现并不复杂(可能我水平比较烂的关系),需要注意的是:推导的过程中我们每条边都考虑了两次,但是只需要输出一次。
假设顶点有n+2个
1号:与2-n相连
2-n号:若x为偶数,则x与 x+2到n+2所有顶点相连,若x为奇数,则x与 x+1到n+2所有顶点相连.
n+1号:与n+2连一条边.
这样一侧就构造完了,另外一侧完全相同(只要加上n+2的偏移量即可)。
最后不要忘了连上两侧的连线,而且对于1的情况要特判(表示当时完全没注意这点)
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1e5+50;
const int INF=0x3f3f3f3f;
int k;
void print(int n,int base)
{
for (int i=2;i<=n-2;i++){
printf("%d %d\n",1+base,i+base);
}
for (int i=2;i<=n-2;i++){
for (int j=i+1;j<=n;j++){
if (j==i+1 && i%2==0) continue;
printf("%d %d\n",i+base,j+base);
}
}
printf("%d %d\n",n-1+base,n+base);
}
void solve(){
if (k==1){
printf("2 1\n1 2\n");
return;
}
int n=(k+2)*2,m=(k+2)*k,base=k+2;
printf("%d %d\n",n,m);
print(k+2,0);
print(k+2,base);
printf("%d %d\n",1,k+3);
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("in.txt","r",stdin);
#endif
while(scanf("%d",&k)!=EOF){
if (k&1){
puts("YES");
solve();
}else puts("NO");
}
return 0;
}