2020.01.17【NOIP提高组】模拟B 组——【中山市选2014】图

Description

一个图有n+m个顶点,顶点分黑白两种颜色,其中编号1~n的为白色顶点,n+1~n+m的为黑色顶点。

对于任意一个白色顶点vi,有且仅有a个不同的白色顶点和b个不同的黑色顶点与之相连。

对于任意一个黑色顶点ui,有且仅有c个不同的白色顶点和d个不同的黑色顶点与之相连。

你的任务是根据给出的a,b,c,d,将原图构造出来,如果有多种构造方案,则输出n+m最小的方案,如果还有多种方案,则输出任意一种。

Input

一行,4个整数a,b,c,d(1<=a,b,c,d<=50),意义如上所述。

Output

第一行两个整数n, m表示有n个白色顶点和m个黑色顶点。

接下来若干行,每行两个整数xi,yi表示标号为xi的顶点和标号为yi的顶点有一条边。编号1~n的为白色顶点,n+1~n+m的为黑色顶点。

你要保证不能出现重复的边(注意,图是双向的)。

Sample Input

1 2 1 2

Sample Output

2 4

1 2

1 3

1 5

2 4

2 6

3 4

3 5

4 6

5 6

Data Constraint

100%的数据,a,b,c,d<=50

赛时

不会,放弃。

正解

一枚构造题:

首先要求出最小的n+m。

因为白点连向b个不同的黑点,黑点连向c个的不同的白点。

所以可得nb=mc,设gcd(b,c)=gc,那么nb/gc=mc/gc,因为gcd(b/gc,c/gc)=1,所以可得n=c/gcS,m=b/gcS(S为正整数)

只要再让S取对应的值使得n、m满足
n>=max(a+1,c),m>=max(d+1,b),bn,cm为偶数即可求得最小n+m。

接下来就是连边。对于黑白连边,只要将黑点拼成一环,然后白点在这个环上按照顺
序依次连b个黑点即可。

同理白点与白点和黑点与黑点类似,对于一个白点(黑点)就是 向后按照顺序依次连所需个数个白点(黑点)即可。

按照顺序依次取的意思是如果上个点连到x,

那么这个点就是从 x的下一个点开始连。注意:点不能与自己连边。

#include<cstdio>
#include<iostream>
using namespace std;
int a,b,c,d,gc,n,m,k;
int f[10000];
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
int main(){
	scanf("%d%d%d%d",&a,&b,&c,&d);
	gc=gcd(b,c);
	for(int i=1;i<=100000;i++){
		n=c/gc*i;m=b/gc*i;
		if(n>=max(a+1,c)&&m>=max(d+1,b)&&a*n%2==0&&d*m%2==0) break;
	}
	printf("%d %d\n",n,m);
	for(int i=1;i<=n;i++)
        for(int j=1;j<=a-f[i];j++){
            k=k%n+1;         
			if(k<=i)  k=i+1;
            f[k]++;
            printf("%d %d\n",i,k);
        }
    k=1;
    for(int i=1;i<=m;i++)
    	for(int j=1;j<=d-f[n+i];j++){
    		k=k%m+1;
    		if(k<=i)k=i+1;
    		f[n+k]++;
    		printf("%d %d\n",n+i,n+k);
		}
    k=0;
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=b;j++){
    		k=k%m+1;
    		printf("%d %d\n",i,n+k);
		}
}
发布了16 篇原创文章 · 获赞 2 · 访问量 1526

猜你喜欢

转载自blog.csdn.net/jay_zai/article/details/104023677
今日推荐