『每日一题 2012-04-17』巧排数字

简介: <p>问题描述:</p> <p><span style="color:rgb(102,102,102); font-family:Arial; font-size:14px">将1,2,3,……,20这20个连续的自然数排成一圈,使任意两个相邻的自然数之和均为素数</span><br></p> <p><span style="color:rgb(102,102,102); font-f

问题描述:

将1,2,3,……,20这20个连续的自然数排成一圈,使任意两个相邻的自然数之和均为素数

强人的思路:

1 找出所有和为素数的数对

2 找Hamilton环

找所有和为素数的数对的方法:

1,2,3,……,20任意两数之和的最大值为39,可取40。故首先,我们找出1到40之间的所有素数,实现函数如下:

int create_prime(int *a, int max)  // 找到  1 到 max 间的所有素数 

{   

    int *x;

    int i,j; 

    x = (int *)alloca(sizeof(int)*(max+1));

    for(i=1;i<=max;i++)  // initialize x[]

        x[i] = 0;

    x[2] = 1;  // 2 是素数

    for(i=3;i<=max;i+=2)

        x[i] = 1;

    

    for(i=3;i<max/3;i+=2)

        for(j=i*3;j<=max;j+=2*i)

            x[j] = 0;

    

    j = 0;

    for(i=0;i<=max;i++)

        if(x[i] == 1)

            a[j++] = i;

    return j; 

}

 

其中,数组a保存找到的1到40之间所有的素数,结果按下标顺序从小到大保存。函数最后返回找到的素数的个数。

然后构建一个map(二维数组)来保存所有和为素数的数对,实现函数如下:

void create_map(void)

{

    int a[20]; // 保存 1 ——40 之间的素数 

    int len;   // 1 -- 40之间素数的个数 

    int i,j,k;

    len = create_prime(a,40);

    for(i=1;i<=20;i++) {

        degree[i] = 0;

        for(j=0;j<len;j++) {

            k = a[j] - i;

            if(k <=0)

                continue;

            if(k <= 20)

                map[i][degree[i]++] = k;

            else

                break;

        }

    }

}

找Hamilton环的实现,就是回溯搜索(类似于堆栈)的方法,来找出所有符合条件的结果。

这里要注意考虑清楚 前进 和回退 条件。实现为:

int main()

{

    int i,j;

    create_map();

    for(i=1;i<=20;i++)

    {

        printf("%d:\t",i);

        for(j=0;j<degree[i];j++)

        {

            printf("%d\t",map[i][j]);

        }

        printf("\n");

    }

    

    ham[0] = 1; // 第一个节点选择的数字 为 1

    ham_len = 1;

    

    for(i=0;i<=20;i++) 

    {

        cur_use[i] = 0;

        cur_pos[i] = 0;

    }

    cur_use[1] = 1;

        

    j = 1; //下个需要处理的数字

    

    cur_pos[1] = 0;

    while(1)

    {

        while(cur_pos[j]<degree[j])

        {

            if(cur_use[map[j][cur_pos[j]]] == 0) //找到了可用数字 

            {

                cur_use[map[j][cur_pos[j]]] = 1;

                ham[ham_len++] = map[j][cur_pos[j]];

                break;

            }

            cur_pos[j]++;

        }

        

        if(cur_pos[j] < degree[j]) 

        {           

            if(ham_len==20 && map[ham[19]][0]==1)

            {

                for(i=0;i<20;i++)

                    printf("%d->",ham[i]);

                printf("\n");

                system("pause");

            }

            else

            {

                j = ham[ham_len-1];

                cur_pos[j] = 0;

                

                continue;

            }            

        }

        

        if(--ham_len <= 0)

            break;

        cur_use[ham[ham_len]] = 0;

        j = ham[ham_len-1];

        cur_pos[j]++;  

    } 

    system("pause");

    return 0;

}


目录
相关文章
【力扣每日一题】1365. 有多少小于当前数字的数字
【力扣每日一题】1365. 有多少小于当前数字的数字
|
5月前
|
存储 容器
【LeetCode刷题】只出现一次的数字(Ⅰ、Ⅱ、Ⅲ)
【LeetCode刷题】只出现一次的数字(Ⅰ、Ⅱ、Ⅲ)
|
6月前
每日一题——只出现一次的数字(II)
每日一题——只出现一次的数字(II)
每日一题——只出现一次的数字(II)
|
6月前
每日一题——只出现一次的数字(III)
每日一题——只出现一次的数字(III)
|
6月前
每日一题——只出现一次的数字
每日一题——只出现一次的数字
|
6月前
|
Java
每日一题《剑指offer》数组篇之和为S的两个数字
每日一题《剑指offer》数组篇之和为S的两个数字
43 0
每日一题《剑指offer》数组篇之和为S的两个数字
|
Java Python
leetcode每日一题.136:只出现一次的数字
leetcode每日一题.136:只出现一次的数字
56 0
|
存储
剑指offer 63. 和为S的两个数字
剑指offer 63. 和为S的两个数字
77 0
|
算法 C++ Python
每日算法系列【LeetCode 面试题 17.05】字母与数字
每日算法系列【LeetCode 面试题 17.05】字母与数字
LeetCode每日一题——902. 最大为 N 的数字组合
给定一个按 非递减顺序 排列的数字数组 digits 。你可以用任意次数 digits[i] 来写的数字。例如,如果 digits = [‘1’,‘3’,‘5’],我们可以写数字,如 ‘13’, ‘551’, 和 ‘1351315’。
96 0
LeetCode每日一题——902. 最大为 N 的数字组合