codeforces #306 D 550D D. Regular Bridge(构造+图论)

来源:互联网 发布:mac repo 下载失败 编辑:程序博客网 时间:2024/05/21 11:28

题目链接:

点击打开链接

题目大意:

给定一个k,代表一个无向联通图的每个点的度数,这个图必须有至少一个桥,构造这个图

题目分析:

头一次做这种构造的题,感觉还是很有趣的~~~

首先考虑这个图一定存在桥,因为每个点的度数都是k,所以如果拆掉其中一个桥,得到两个联通图,因无向联通图的总度数一定是偶数,假设第一个图有n1个点,第二个图有n2个点,第一个图的度数为n1*k-1,第二个图为n2*k-1,所以k一定是奇数,n1,n2也必须是奇数才可以构造出这种图

那么继续考虑当k是奇数时,我们考虑构造桥两边的一个对称的图,因为只要存在一个无向连通图有n-1个度数为k的点和一个k-1度数点即可,那么就可以通过连一个桥,得到题目要求的图。

首先考虑,度数为k-1的点一定连者k-1个不同的点,所以先构造出这个图,那么,再考虑如果多添加两个点的话,能够给这个k-1个点提供2个度数,然后他们自己再相连能够导致度数为k,因为k-1一定是偶数(k是奇数),所以利用这种方法就能构造出图来,

还有一种更加简单的方法,也就是考虑正多边形的性质,连成一个正多边形,可以给每个点连向其他的k-2个点,直接得到k-2的度数,但是这样会多出一个度数,而加点的方法又只能提供2的倍数的度数,那么考虑怎么办?

可以把这k-1个点看成是连成的正多边形,只要不连对角线就可以了。。。

我是按照第二种做法做的,代码很好实现复杂度是k^2

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;int k;int front( int x ){    if ( x == 2 )        return k;    else return x-1;}int back ( int x ){    if ( x == k )        return 2;    else return x+1;} int mid ( int x ){    if ( x + (k-1)/2 <= k )        return x + (k-1)/2;    else return x -( k-1)/2;}int main ( ){    while ( ~scanf ( "%d" , &k ) )    {        int n = (k+2)*2;        int m = n*k/2;        if ( k%2 == 0 )        {            puts("NO");            continue;        }        puts("YES");        if ( k == 1 )        {            printf ( "2 1\n" );            printf ( "1 2\n" );            continue;        }        printf ( "%d %d\n" , n , m );        //connect the bridge        printf ( "%d %d\n" , 1 , k+3 );        for ( int i = 2 ; i <= k ; i++ )        {            printf ( "%d %d\n" , 1 , i );            printf ( "%d %d\n" , k+3 , i+k+2 );         }        for ( int i = 2 ; i <= k ; i++ )        {            printf ( "%d %d\n" , i , k+1 );            printf ( "%d %d\n" , i+k+2 , 2*k+3 );            printf ( "%d %d\n" , i , k+2 );            printf ( "%d %d\n" , i+k+2 , 2*k+4 );        }        printf ( "%d %d\n" , k+1 , k+2 );        printf ( "%d %d\n" , 2*k+3 , 2*k+4 );        for ( int i = 2 ; i < k ; i++ )            for ( int j = i+1 ; j <= k ;j++ )            {                if ( j == front(i) || j == back(i) || j == mid(i) )                    continue;                printf ( "%d %d\n" , i , j );                printf ( "%d %d\n" , k+2+i , j+k+2 );            }        for ( int i = 2 ; i <= k ; i++ )        {            if ( k == 3 )                break;            if ( i == k )             {                printf ( "%d %d\n" , i , 2 );                printf ( "%d %d\n" , i+k+2 , k+4 );            }            else             {                printf ( "%d %d\n" , i , i+1 );                printf ( "%d %d\n" , i+k+2 , i+k+3 );            }        }        /*for ( int i = 2 ; i <= (k+1)/2 ; i++ )        {            if ( k - 5 <= 0 ) break;               printf ( "%d %d\n" , i , i+ (k-1)/2 ) ;            printf ( "%d %d\n" , i+k+2 , i+ (k-1)/2 + k +2 );        }*/    }}



0 0