算法学习-循环染色方案

题目

用红、蓝两种颜色将围成一圈的8个旗子染色。规定:若某两种染色方案通过旋转的方式可以重合,则只算一种。问:一共有多少种不同的染色方案?

问题分析

用0/1表示颜色方案,8个棋子对应8位二进制数。

”旋转重合则只算一种”即:将x循环左移以为得y,则x和y属于相同类别(等价类):

若y<x,则删除x;

若y>x,则删除y;

该算法借鉴求素数的筛法

由于每个方案只需要计算1次,时间复杂度为O(N)

棋子数目记为n,则N=2的n次方

除了全0和全1以外,所有偶数都是重复的,所有最高位为1都是重复的,根据这两个结论可以适当优化。


代码如下

// 循环左移一位
int RotateShiftLeft(int x, int N)
{
	int hight = (x >> (N - 1));
	x &= ((1<<(N - 1)) - 1);
	x <<= 1;
	x |= hight;
	return x;
}

int Polya(int N, std::list<int>& answer)
{
	int i, j;
	int k1, k2;
	int m = (1 << N);
	int* p = new int[m];  // 记录每种方案
	fill(p, p + m, 1);
	for (i = 0; i < m; i++)  // 遍历所有染色方案
	{
		for (p[i] == 1)   // 尚未删掉
		{
			k1 = i;
			for (j = 0; j <= N; j++)
			{
				k2 = RotateShiftLeft(k1, N);
				if (k2 == i)  // 说明完成了循环
				{
					break;
				}
				if (k2 > i)  // 后面的k2无效
				{
					p[k2] = 0
				}
				else // if (k2 < i)
				{
					p[i] = 0;  // i无效
					break;     // 前面必然便利过
				}
				k1 = k2;
			}
		}
	}
	for (i = 0; i < m; i++)
	{
		if (p[i] == 1)
			answer.push_back(i);
	}
	delete[] p;
	return (int)answer.size();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值