• 《算法竞赛进阶指南》靶形数独


    小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低。

    但普通的数独对他们来说都过于简单了,于是他们向 ZZ 博士请教,ZZ 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。

    靶形数独的方格同普通数独一样,在 9×99×9 的大九宫格中有 99 个 3×33×3 的小九宫格(用粗黑色线隔开的)。

    在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 11 到 99 的数字。

    每个数字在每个小九宫格内不能重复出现,每个数字在每行、每列也不能重复出现。

    但靶形数独有一点和普通数独不同,即每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高(如下图所示)。

    上图具体的分值分布是:最里面一格(黄色区域)为 1010 分,黄色区域外面的一圈(红色区域)每个格子为 99 分,再外面一圈(蓝色区域)每个格子为 88 分,蓝色区域外面一圈(棕色区域)每个格子为 77 分,最外面一圈(白色区域)每个格子为 66 分,如上图所示。

    比赛的要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取更高的总分数。

    而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和。

    如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 28292829。

    游戏规定,将以总分数的高低决出胜负。

    由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能够得到的最高分数。

    输入格式

    输入一共包含 99 行。

    每行 99 个整数(每个数都在 0—90—9 的范围内),表示一个尚未填满的数独方格,未填的空格用 00 表示。

    每两个数字之间用一个空格隔开。

    输出格式

    输出可以得到的靶形数独的最高分数。

    如果这个数独无解,则输出整数 −1−1。

    数据范围

    40%40% 的数据,数独中非 00 数的个数不少于 3030。

    80%80% 的数据,数独中非 00 数的个数不少于 2626。

    100%100% 的数据,数独中非 00 数的个数不少于 2424。

    输入样例:

    1. 7 0 0 9 0 0 0 0 1
    2. 1 0 0 0 0 5 9 0 0
    3. 0 0 0 2 0 0 0 8 0
    4. 0 0 5 0 2 0 0 0 3
    5. 0 0 0 0 0 0 6 4 8
    6. 4 1 3 0 0 0 0 0 0
    7. 0 0 7 0 0 2 0 9 0
    8. 2 0 1 0 6 0 8 0 4
    9. 0 8 0 5 0 4 0 1 2

    输出样例:

    2829

    思路,代码与这题基本相同 (4条消息) 《算法竞赛进阶指南》数独_wsh1931的博客-CSDN博客

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. const int N = 9, M = 1 << N;
    6. int ans = - 1;
    7. int map[M];
    8. int ones[M];
    9. int g[N][N];
    10. int row[N], col[N], cell[3][3];
    11. void init()
    12. {
    13. for (int i = 0; i < M; i ++ )
    14. for (int j = 0; j < N; j ++ )
    15. if (i >> j & 1) ones[i] ++ ;
    16. for (int i = 0; i < N; i ++ ) map[1 << i] = i;
    17. for (int i = 0; i < N; i ++ ) row[i] = M - 1;
    18. for (int i = 0; i < N; i ++ ) col[i] = M - 1;
    19. for (int i = 0; i < 3; i ++ )
    20. for (int j = 0; j < 3; j ++ )
    21. cell[i][j] = M - 1;
    22. }
    23. int lowbit(int x)
    24. {
    25. return x & - x;
    26. }
    27. void draw(int x, int y, int t, int is_insert)
    28. {
    29. if (is_insert) g[x][y] = t;
    30. else g[x][y] = 0;
    31. t -- ;
    32. int v = 1 << t;
    33. if (!is_insert) v = - v;
    34. row[x] -= v;
    35. col[y] -= v;
    36. cell[x / 3][y / 3] -= v;
    37. }
    38. int get(int x, int y)
    39. {
    40. return row[x] & col[y] & cell[x / 3][y / 3];
    41. }
    42. int get_score(int x, int y, int score)
    43. {
    44. return (min(min(x, 8 - x), min(y, 8 - y)) + 6) * score;
    45. }
    46. void dfs(int cnt, int score)
    47. {
    48. if (!cnt)
    49. {
    50. ans = max(score, ans);
    51. return ;
    52. }
    53. int x, y;
    54. int mins = 10;
    55. for (int i = 0; i < N; i ++ )
    56. for (int j = 0; j < N; j ++ )
    57. {
    58. if (!g[i][j])
    59. {
    60. int t = ones[get(i, j)];
    61. if (mins > t)
    62. {
    63. x = i;
    64. y = j;
    65. mins = t;
    66. }
    67. }
    68. }
    69. int state = get(x, y);
    70. for (int i = state; i ; i -= lowbit(i))
    71. {
    72. int t = map[lowbit(i)] + 1;
    73. draw(x, y, t, true);
    74. dfs(cnt - 1, score + get_score(x, y, t));
    75. draw(x, y, t, false);
    76. }
    77. }
    78. int main()
    79. {
    80. init();
    81. int cnt = 0, score = 0;
    82. for (int i = 0; i < N; i ++ )
    83. for (int j = 0; j < N; j ++ )
    84. {
    85. int x;
    86. scanf("%d", &x);
    87. if (x)
    88. {
    89. draw(i, j, x, true);
    90. score += get_score(i, j, x);
    91. }
    92. else cnt ++ ;
    93. }
    94. dfs(cnt, score);
    95. cout << ans << endl;
    96. return 0;
    97. }

     

  • 相关阅读:
    【AI设计模式】01-数据表示-特征哈希(Feature Hashed)模式
    猿创征文|【Typescript入门】常用数据类型(3)
    RS485信号的测量
    java毕业设计——基于java+jsp+Tomcat的电子书下载系统设计与实现(毕业论文+程序源码)——电子书下载系统
    线程交互现象
    qt程序中,如何做才能用到OpenGL ES图形api
    基于Python GDAL为长时间序列遥感图像绘制时相变化曲线图
    node的文件系统和数据流
    Ubuntu 安装 MySQL 8.23
    线段树
  • 原文地址:https://blog.csdn.net/qq_61935738/article/details/126027009