m1.cpp

来自「给定整数n」· C++ 代码 · 共 90 行

CPP
90
字号
#include <stdio.h>

//给定整数n,产生所有[2n]上的匹配(matching)
//将其视为一个所有块大小均为2的集合分拆
//输出格式为 a1 a2 - b1 b2 - c1 c2 - ...
//满足a1<a2, b1<b2, ...
//且 a1 < b1 < c1 <...
//时间大约30s


//算法思想如下:
//将集合中的元素以数组a[i]来表示
//初始分拆为1234...,依次产生新的分拆
//直至找不到p使得a[2p]<a[2p+2]

//产生新的分拆方法为:
//1. 找到a[2p]<a[2p+2]
//2. 将a[2p]和它后面比它大的最小元素x互换
//3. 将a[2p]后面的元素顺序排列

//在2中有两种情况,一种是x为某个a[2q],另一种是x为奇数位。
//注意到a[2q]递减而a[2q+1]递增,
//我们可以首先从前往后检查a[2q],
//然后再从后往前检查a[2q+1]

//在进行排序的时候,注意到a[2p]和x交换不影响顺序,
//我们可以直接将a[2p]之后的元素交错排列即可,
//即其顺序为a[2p+1]<a[2p+3]<...<a[2n-1]<a[2n]<a[2n-2]<...<a[2p+2]

void main()
{

	int i,p,q,n,tmp;
	long int tnum;

	int a[21],b[21];
	
	n=3;

	for (i=1;i<=2*n;i++) a[i]=i;
	tnum=0;

	while (n>0) 
	{	
		
		//输出匹配
		tnum++;
		for (i=1;i<n;i++)
			printf("%d%d-",a[2*i-1],a[2*i]);
		printf("%d%d\n",a[2*n-1],a[2*n]);
		
		//查找下一个匹配
		p=n-1;
		while ((p>0) && (a[2*p]>a[2*p+2])) p--;  //查找第一个顺序的偶数位。
		
		if (p==0) 
			break;
		else
		{
			q=p+1; tmp=a[2*p];
			while ((q<n) && (a[2*q+2]>tmp)) q++;  //查找最后一个比a[2*p]大的偶数位——2q
			if (q<n)
			{
				a[2*p]=a[2*q]; a[2*q]=tmp; //交换a[2p]和a[2q]
			}
			else
			{
				while (a[2*q-1]>tmp) q--;  //查找第一个比a[2*p]大的奇数位——2q+1
				if (q==n) 
				{
					a[2*p]=a[2*n]; a[2*n]=tmp; //如果没有找到,2n就是比a[2p]大的最近的一个。
				}
				else
				{
					a[2*p]=a[2*q+1]; a[2*q+1]=tmp; //交换a[2p]和a[2q+1]
				}
			}

			//重排a[2p]之后的数字
			for (i=p+1;i<=n;i++) 
			{
				b[i-p]=a[2*i-1]; b[n-2*p+i]=a[2*(n+p+1-i)];
			}
			for (i=2*p+1;i<=2*n;i++) a[i]=b[i-2*p];

		}
	} 
	printf("%d\n",tnum);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?