求一个图,每个点的度数都为K而且必须至少要有一个桥.
构造题:
只有k为奇数的时候有解, 构造这样的一个图,左边一团有 k+1 个点 , 右边一团也有 k+1 个点, 中间经过 m1 , m2 连着一个桥.
如果左右两团是完全图,则每个点的度数都为k, 现在考虑如何通过m1,m2连接起来而又不改变度数.
显然这个图是对称的,只考虑左边和点m1,m1和m2是一个桥,要连一条边,m1 和左边的团某个点A要连在一起,又要连一条边,这时A点的度数多了,要和团里的其他点B断掉一条边,为了保持B的度数不变,B再连一条边到m1,这时m1的度就至少为3了,然后将m1的度补全. 每次从左边团中删掉一条边,然后将这条边的两个点连到m1上就可以了.m1的度每次增加2,所以如果k为奇数的话都可以用这样的方法构造出来.
import java.util.*;
import java.math.*;
public class Main
{
int k,midl,midr;
boolean[][] edge = new boolean[330][330];
boolean[] used = new boolean[330];
void cut_and_link(int from,int to,int goal)
{
int tk=k-3;
while(tk>0)
{
boolean flag=false;
for(int i=from;i<to&&flag==false;i++)
{
if(used[i]==true) continue;
for(int j=i+1;j<to;j++)
{
if(i==2*k+4||i==4+k||i==1+k||i==1) continue;
if(j==2*k+4||j==4+k||j==1+k||j==1) continue;
if(used[j]==true) continue;
if(edge[i][j]==true)
{
used[i]=used[j]=true;
//cut
edge[i][j]=edge[j][i]=false;
//link
edge[i][goal]=edge[goal][i]=true;
edge[j][goal]=edge[goal][j]=true;
// flag
flag=true;
break;
}
}
}
tk-=2;
}
}
void build_tuan(int from ,int to)
{
for(int i=from;i<=to;i++)
{
for(int j=i+1;j<=to;j++)
{
edge[i][j]=edge[j][i]=true;
}
}
}
void sovle(int k)
{
midl=k+2; midr=k+3;
build_tuan(1,k+1);
edge[1][midl]=edge[midl][1]=true;
edge[1][k+1]=edge[k+1][1]=false;
edge[k+1][midl]=edge[midl][k+1]=true;
cut_and_link(2,k+1,midl);
edge[midl][midr]=edge[midr][midl]=true;
build_tuan(k+4,2*k+4);
edge[2*k+4][midr]=edge[midr][2*k+4]=true;
edge[k+4][2*k+4]=edge[2*k+4][k+4]=false;
edge[k+4][midr]=edge[midr][k+4]=true;
cut_and_link(k+4,2*k+4,midr);
}
Main()
{
Scanner in = new Scanner(System.in);
k=in.nextInt();
if(k%2==0)
{
System.out.println("No");
return ;
}
System.out.println("Yes");
if(k==1)
{
System.out.println("2 1\n1 2");
}
else
{
sovle(k);
int num=2*k+4,cnt=0;
for(int i=1;i<=num;i++)
for(int j=i+1;j<=num;j++)
if(edge[i][j]) cnt++;
System.out.printf("%d %d\n",num,cnt);
for(int i=1;i<=num;i++)
{
for(int j=i+1;j<=num;j++)
{
if(edge[i][j])
{
System.out.printf("%d %d\n",i,j);
}
}
}
}
}
public static void main(String[] args)
{
new Main();
}
}