哈密顿回路-相异数字序列问题

文章探讨了哈密顿回路的概念,即在图论中经过所有顶点一次且仅一次的回路,并介绍了如何构建满足特定条件的0,1序列,确保形成互不相同的十进制数。通过实例分析了当m为2和3时的序列构造过程,揭示了这一问题的解决方案。" 122732002,8753399,VTK实战:如何根据颜色获取对比色,"['图形渲染', 'c++', '计算机图形学']

要满足两个条件:

  1.封闭的环

  2.是一个连通图,且图中任意两点可达

  经过图(有向图或无向图)中所有顶点一次且仅一次的通路称为哈密顿通路。

  经过图中所有顶点一次且仅一次的回路称为哈密顿回路。

  具有哈密顿回路的图称为哈密顿图,具有哈密顿通路但不具有哈密顿回路的图称为半哈密顿图。

  平凡图是哈密顿图。


问题描述
给你一个整数m,找出这样一个长为2^m的0,1序列,使得依次取长为m的串时,得到的2^m个长为m的0,1串,它们表示了互不相同的十进制数。
输入:第一行是一个整数n,表示需考察n个整数(1<=n<=15),接着n行,每行有一个整数m(1<=m<=15)
样例:
2
2
3
m=2: 0011
m=3: 00010111
考察m=2的情形,长为2的序列00开始,每个序列后面接0或1,于是接0得000,前面两位00和后面两位的00相同,应排除本次接0的情况,应接1,变成001,后01与前00不同,应保留填上1.确定01后,对01后面接0或1,应该有010和011,都可行,取低2位10或11,类似接0或1.最后得出下面有向图。

#include <iostream>
using namespace std;
#define MAXN 65535
struct node 
{
 int left, right; // left,right分别记录当前节点通过添0,添1而得的序列
 int visited; // 标记是否被访问到,-1表示未访问过,0表示左支,1表示右支
};

typedef node NODE;
NODE p[MAXN]; // 表示节点数组
long maxb, a[MAXN]; // a存放最优解
int m;

void init(int m) // 初始化构建一个有向图
{
 long i, k;
 maxb = (1<<m) - 1; // 记有向图的顶点最大顶点数-1
 for (i = 0; i <= maxb; i++)
 {
  // 设定无左右儿子,无访问值
  p[i].left = -1;
  p[i].right = -1;
  p[i].visited = -1;
  k = i; // 考察当前十进制数是i的节点的左右儿子生成情况
  k = (k << 1) & maxb; // 节点的二进制数尾添0,用位操作,取后m位
  if (k != i)
  {
   p[i].left = k; // 去左支重复节点
  }
  k = k + 1; // 尝试右支
  if (k != i)
  {
   p[i].right = k; // 去右支重复节点
  }
 }
}

// 判断数b与当前部分解a前k个是否有相同的
bool NotEqual(int k, int b)
{
 bool flag = true;
 int i;
 for (i = 0; i <= k; i++)
 {
  if (a[i] == b)
  {
   flag = false;
   break;
  }
 }
 return flag;
}

// 求最优解a,采用迭代回溯算法
void Compt()
{
 long  i = 1, j;
 bool flag = false;
 a[0] = 0;
 p[0].visited = 0;
 while (true) // 搜索子树
 {
  while (i <= maxb && p[a[i-1]].left != -1 && p[a[i-1]].left != 0
   && NotEqual(i-1, p[a[i-1]].left))
  {// 如左子树一直可行,沿左子树一直下去
   a[i] = p[a[i-1]].left; //取左儿子值
   p[a[i-1]].visited = 0; //设访问左儿子标志
   i++;
   flag = false; // 设定可能进入右子树标志
  }
  // 如果个数已经够了,直接输出结果
  if (i > maxb)
  {
   for (j = 0; j <= maxb; j++)
   {
    cout << ((a[j]&(1<<(m-1)))>>(m-1)); // 按字符串输出
   }
   cout << endl;
   return;
  }
  else // 如果个数未满足要求
  {
   // 若右子树可行进入右子树
   if (p[a[i-1]].right != -1 && p[a[i-1]].right != 0 && NotEqual(i-1, p[a[i-1]].right))
   {
    a[i] = p[a[i-1]].right; //取右儿子值
    p[a[i-1]].visited = 0; //设访问右儿子标志
    i++;
    flag = false; // 设定可能进入左子树标志
   }
  }
  while (!flag) // 剪枝回溯
  {
   i--;
   while (i > 0 && p[a[i-1]].visited == 1) // 沿右子树返回
   {
    a[i] = -1;
    p[a[i-1]].visited = -1; // 取消访问标志
    i--;
   }
   if (p[a[i-1]].right != -1 && p[a[i-1]].right != 0 && NotEqual(i-1, p[a[i-1]].right))
   {
    a[i] = p[a[i-1]].right; //取右儿子值
    p[a[i-1]].visited = 1; //设访问右儿子标志
    i++;
    flag = true; // 设定可能进入左子树标志
   }
  }
 
 }
}

int main()
{
 int i, n;
 cin >> n;
 for (i = 0; i < n; i++)
 {
  cin >> m;
  cout << "m=" << m << ":" << endl;
  if (m <= 0)
  {
   cout << "Impossible!" << endl;
  }
  else
  {
   init(m);
   Compt();
  }
 }
 system("pause");
 return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值