作者共发了5篇帖子。 内容转换:不转换▼
 
点击 回复
403 4
【试题】2016蓝桥杯省赛C/C++B组第7题 剪邮票
一派护法 十九级
1楼 发表于:2016-5-22 17:07
剪邮票


如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。


请你计算,一共有多少种不同的剪取方法。


请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

题目请参见:http://blog.csdn.net/eventqueue/article/details/50954641

本文是参考下面帖子中10楼的解法:
http://tieba.baidu.com/p/4425964968
一派护法 十九级
2楼 发表于:2016-5-22 17:08
【C语言代码】
#include <stdio.h>

#define A arr[0]
#define B arr[1]
#define C arr[2]
#define D arr[3]
#define E arr[4]

int arr[5]; // 原数组
int map[] = {-9999, 1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14}; // 原数与修正数的对应关系, 0没有修正数对应
int dir[4] = {-1, -5, 1, 5}; // 修正数 + 方向 = 新修正数

// 判断一个修正数是否在修正数组中
int in(int n)
{
    int i;
    for (i = 0; i < 5; i++)
    {
        if (map[arr[i]] == n)
            return 1;
    }
    return 0;
}

// 合法性判定: 至少有4个相邻面的交线, 且每个块至少有一个相邻面的交线
int check(void)
{
    int m, m_new;
    int i, j, k;
    int found;

    int faces[4][2]; // 相邻的面
    int faces_num = 0; // 相邻的面数

    for (i = 0; i < 5; i++) // 扫描每个块
    {
        m = map[arr[i]]; // 当前块的修正数
        found = 0; // 当前块与多少个方格相邻
        for (j = 0; j < 4; j++) // 扫描当前块的四个方向
        {
            m_new = m + dir[j]; // 该方向的修正数
            if (in(m_new)) // 如果修正数在arr数组中, 表示两方格相邻
            {
                found++;

                if (faces_num < 4) // faces数组最多只能存4个相邻面交线数据
                {
                    // 判断该面交线是否已经存到了faces数组中
                    for (k = 0; k < faces_num; k++)
                    {
                        if ((faces[k][0] == m && faces[k][1] == m_new) || (faces[k][1] == m && faces[k][0] == m_new))
                            break;
                    }
                    // 如果没有就添加进去, 然后把faces_num的值+1
                    if (k == faces_num) // 循环不是因为break结束
                    {
                        // 大小顺序不定
                        faces[faces_num][0] = m;
                        faces[faces_num][1] = m_new;
                        faces_num++;
                    }
                }
            }
        }
        if (found == 0)
            return 0; // 每个块至少有一个相邻的面
    }
    return (faces_num >= 4);
}

int main(void)
{
    int cnt = 0;

    // 生成C5_12组合的简易方法
    for (A = 1; A <= 12; A++)
    {
        for (B = A + 1; B <= 12; B++)
        {
            for (C = B + 1; C <= 12; C++)
            {
                for (D = C + 1; D <= 12; D++)
                {
                    for (E = D + 1; E <= 12; E++)
                    {
                        if (check())
                        {
                            cnt++;
                            printf("[%d] %d %d %d %d %d\n", cnt, A, B, C, D, E);
                        }
                    }
                }
            }
        }
    }

    printf("总数: %d\n", cnt);

    return 0;
}
一派护法 十九级
3楼 发表于:2016-5-22 17:08
【运行结果】
[1] 1 2 3 4 5
[2] 1 2 3 4 6
[3] 1 2 3 4 7
[4] 1 2 3 4 8
[5] 1 2 3 5 6
[6] 1 2 3 5 7
[7] 1 2 3 5 9
[8] 1 2 3 6 7
[9] 1 2 3 6 10
[10] 1 2 3 7 8
[11] 1 2 3 7 11
[12] 1 2 5 6 7
[13] 1 2 5 6 9
[14] 1 2 5 6 10
[15] 1 2 5 9 10
[16] 1 2 6 7 8
[17] 1 2 6 7 10
[18] 1 2 6 7 11
[19] 1 2 6 9 10
[20] 1 2 6 10 11
[21] 1 3 5 6 7
[22] 1 5 6 7 8
[23] 1 5 6 7 9
[24] 1 5 6 7 10
[25] 1 5 6 7 11
[26] 1 5 6 9 10
[27] 1 5 6 10 11
[28] 1 5 9 10 11
[29] 2 3 4 5 6
[30] 2 3 4 6 7
[31] 2 3 4 6 8
[32] 2 3 4 6 10
[33] 2 3 4 7 8
[34] 2 3 4 7 11
[35] 2 3 4 8 12
[36] 2 3 5 6 7
[37] 2 3 5 6 9
[38] 2 3 5 6 10
[39] 2 3 6 7 8
[40] 2 3 6 7 10
[41] 2 3 6 7 11
[42] 2 3 6 9 10
[43] 2 3 6 10 11
[44] 2 3 7 8 11
[45] 2 3 7 8 12
[46] 2 3 7 10 11
[47] 2 3 7 11 12
[48] 2 4 6 7 8
[49] 2 5 6 7 8
[50] 2 5 6 7 9
[51] 2 5 6 7 10
[52] 2 5 6 7 11
[53] 2 5 6 9 10
[54] 2 5 6 10 11
[55] 2 6 7 8 10
[56] 2 6 7 8 11
[57] 2 6 7 8 12
[58] 2 6 7 9 10
[59] 2 6 7 10 11
[60] 2 6 7 11 12
[61] 2 6 9 10 11
[62] 2 6 10 11 12
[63] 3 4 5 6 7
[64] 3 4 6 7 8
[65] 3 4 6 7 10
[66] 3 4 6 7 11
[67] 3 4 7 8 11
[68] 3 4 7 8 12
[69] 3 4 7 10 11
[70] 3 4 7 11 12
[71] 3 4 8 11 12
[72] 3 5 6 7 8
[73] 3 5 6 7 9
[74] 3 5 6 7 10
[75] 3 5 6 7 11
[76] 3 6 7 8 10
[77] 3 6 7 8 11
[78] 3 6 7 8 12
[79] 3 6 7 9 10
[80] 3 6 7 10 11
[81] 3 6 7 11 12
[82] 3 7 8 10 11
[83] 3 7 8 11 12
[84] 3 7 9 10 11
[85] 3 7 10 11 12
[86] 4 5 6 7 8
[87] 4 6 7 8 10
[88] 4 6 7 8 11
[89] 4 6 7 8 12
[90] 4 7 8 10 11
[91] 4 7 8 11 12
[92] 4 8 10 11 12
[93] 5 6 7 8 9
[94] 5 6 7 8 10
[95] 5 6 7 8 11
[96] 5 6 7 8 12
[97] 5 6 7 9 10
[98] 5 6 7 9 11
[99] 5 6 7 10 11
[100] 5 6 7 11 12
[101] 5 6 9 10 11
[102] 5 6 10 11 12
[103] 5 7 9 10 11
[104] 5 9 10 11 12
[105] 6 7 8 9 10
[106] 6 7 8 10 11
[107] 6 7 8 10 12
[108] 6 7 8 11 12
[109] 6 7 9 10 11
[110] 6 7 10 11 12
[111] 6 8 10 11 12
[112] 6 9 10 11 12
[113] 7 8 9 10 11
[114] 7 8 10 11 12
[115] 7 9 10 11 12
[116] 8 9 10 11 12
总数: 116
一派护法 十九级
4楼 发表于:2016-5-22 17:10
【合法性判定方法】
至少有N - 1个面交线, 且每个方格都至少有一个面交线
N为剪下来的方格总数
一派护法 十九级
5楼 发表于:2016-5-22 17:15
【什么是修正数】
参考资料:http://blog.csdn.net/u014552756/article/details/50946197
原题中12个格子是这样编号的:
1  2   3  4
5  6   7   8
9 10 11 12
向上为-4,向下为+4,向左为-1,向右为+1
但是位于边界的数会出现问题,所以重新编号:
1     2    3  4
6     7    8  9
11 12 13 14
向上变为-5,向下为+5
这样6向左为5,而5不可能在剪下的邮票(arr)中存在,方便判断。

在用5个for循环生成组合时,使用原编号
在判断时,通过map数组转换成修正编号

回复帖子

内容:
用户名: 您目前是匿名发表
验证码:
(快捷键:Ctrl+Enter)
 

本帖信息

点击数:403 回复数:4
评论数: ?
作者:巨大八爪鱼
最后回复:巨大八爪鱼
最后回复时间:2016-5-22 17:15
 
©2010-2024 Arslanbar Ver2.0
除非另有声明,本站采用知识共享署名-相同方式共享 3.0 Unported许可协议进行许可。