Codeforces 550D —— Regular Bridge——————【构造】
题目大意:给你一个k。让你构造一个无向图,最少有一条桥,保证这个图中的所有顶点的度都为k。如果有这样的图,输出顶点数和边数,同时还有所有边的端点。
解题思路:首先我们证明k不能是偶数,假设结点u和v关于一条桥邻接,那么如果去掉该桥后,对于包含u结点的连通分量来说,只有u结点是奇数,那么这与连通分量中所有结点的度的和为偶数相矛盾,得证k只能为奇数。
讨论k为奇数:我们假定结点1是由桥所连接的结点,那么想让1结点度数为k,那么就要有k-1个结点与1邻接,我们假设是2->k,这k-1个结点就算是行成完全图也不能保证度数为k,所以需要加一个结点k+1,让k+1先与2->k这k-1个结点相连,但是k+1结点的度才为k-1,所以我们仍然需要加结点k+2,让k+2也与2->k都连接,同时让k+1与k+2连接。保证了k+1和k+2度都为k。但是这时候2->k这k-1个结点度数都才为3。如果让2->k这k-1个结点行成完全图,那么每个结点会增加k-2个度,但是现在需要每个结点增加k-3个度,所以需要每个结点减少1个度。我们可以假设删去2 -> 3, 4 -> 5,6->7.....这些边。到这里我们的构造算法已经结束了。
构造算法为:让1、k+1、k+2跟2->k这k-1个结点邻接,同时让2->k这k-1个结点形成完全图,但是删除env->env+1,env为2->k中所有偶数。同时桥所连接的那一边是对称的处理。
#include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> #include<string> #include<iostream> #include<queue> #include<stack> #include<map> #include<vector> #include<set> using namespace std; typedef long long LL; #define mid (L+R)/2 #define lson rt*2,L,mid #define rson rt*2+1,mid+1,R #pragma comment(linker, "/STACK:102400000,102400000") const int maxn = 1e5 + 300; const int INF = 0x3f3f3f3f; typedef long long LL; typedef unsigned long long ULL; int main() { int k; scanf ( "%d", &k ); if ( k == 1 ) { puts ("YES\n2 1\n1 2"); }else if ( k % 2 == 0 ) { puts ( "NO" ); }else { puts ( "YES" ); printf ( "%d %d\n", 2*k + 4, k*(k+2) ); for ( int i = 2; i <= k; i++ ) { printf ( "1 %d\n", i ); } int nn = k + 2; for ( int i = 2; i <= k; i++ ) { printf("%d %d\n",i, k+1); printf("%d %d\n",i, k+2); for ( int j = i + 1; j <= k; j++ ) { if(i%2 == 0 && j == i+1) continue; printf ( "%d %d\n", i, j ); } } printf ( "%d %d\n", k + 1, k + 2 ); for ( int i = 2; i <= k; i++ ) { printf ( "%d %d\n", 1 + nn, i + nn ); } for ( int i = 2; i <= k; i++ ) { printf("%d %d\n",i+nn, nn+k+1); printf("%d %d\n",i+nn, nn+k+2); for ( int j = i + 1; j <= k; j++ ) { if(i%2 == 0 && j == i+1) continue; printf ( "%d %d\n", i + nn, j + nn ); } } printf ( "%d %d\n", k + 1 + nn, k + 2 + nn ); printf ( "%d %d\n", 1, nn + 1 ); } return 0; }
学学学 练练练 刷刷刷