蓝桥杯 2012 5 方块填数

来源:互联网 发布:数据散修txt下载 编辑:程序博客网 时间:2024/04/28 18:57

“数独”是当下炙手可热的智力游戏。一般认为它的起源是“拉丁方块”,是大数学家欧拉于1783年发明的。
如图这里写图片描述所示:6x6的小格被分为6个部分(图中用不同的颜色区分),每个部分含有6个小格(以下也称为分组)。
开始的时候,某些小格中已经填写了字母(ABCDEF之一)。需要在所有剩下的小格中补填字母。
全部填好后,必须满足如下约束:
1. 所填字母只允许是A,B,C,D,E,F 中的某一个。
2. 每行的6个小格中,所填写的字母不能重复。
3. 每列的6个小格中,所填写的字母不能重复。
4. 每个分组(参见图中不同颜色表示)包含的6个小格中,所填写的字母不能重复。
为了表示上的方便,我们用下面的6阶方阵来表示图[1.jpg]对应的分组情况(组号为0~5):
000011
022013
221113
243333
244455
445555
用下面的数据表示其已有字母的填写情况:
02C
03B
05A
20D
35E
53F
很明显,第一列表示行号,第二列表示列号,第三列表示填写的字母。行号、列号都从0开始计算。
一种可行的填写方案(此题刚好答案唯一)为:
E F C B D A
A C E D F B
D A B E C F
F B D C A E
B D F A E C
C E A F B D
你的任务是:编写程序,对一般的拉丁方块问题求解,如果多解,要求找到所有解。
【输入、输出格式要求】
用户首先输入6行数据,表示拉丁方块的分组情况。
接着用户输入一个整数n (n<36), 表示接下来的数据行数
接着输入n行数据,每行表示一个预先填写的字母。
程序则输出所有可能的解(各个解间的顺序不重要)。
每个解占用7行。
即,先输出一个整数,表示该解的序号(从1开始),接着输出一个6x6的字母方阵,表示该解。
解的字母之间用空格分开。
如果找不到任何满足条件的解,则输出“无解”
例如:用户输入:

000011022013221113243333244455445555602C03B05A20D35E53F
则程序输出:
1E F C B D AA C E D F BD A B E C FF B D C A EB D F A E CC E A F B D

再如,用户输入:

001111002113022243022443544433555553704B05A13D14C24E50C51A
则程序输出:
1D C E F B AE F A D C BA B F C E DB E D A F CF D C B A EC A B E D F2D C E F B AE F A D C BA D F B E CB E C A F DF B D C A EC A B E D F3D C F E B AA E B D C FF D A C E BB F E A D CE B C F A DC A D B F E4D C F E B AB E A D C FA D C F E BF B E A D CE F B C A DC A D B F E5D C F E B AE F A D C BA B C F E DB E D A F CF D B C A EC A E B D F6D C F E B AE F A D C BA B D F E CB E C A F DF D B C A EC A E B D F7D C F E B AE F A D C BA D B F E CB E C A F DF B D C A EC A E B D F8D C F E B AF E A D C BA D B C E FB F E A D CE B C F A DC A D B F E9D C F E B AF E A D C BA F C B E DB D E A F CE B D C A FC A B F D E

组合数学里著名的拉丁方问题,但是这题只要DFS就好了.同样采用链表优化,x方向限定,待选集合是bx
然后by, bg同时判重 y方向和 不同颜色的方块
然后DFS就好,注意同样不要在DFS中输出,先把答案存下来.这个在我的系统里面会段错误.

#include <bits/stdc++.h>using namespace std;char g[6][6], ans[6][6];list<char> bx[6];bool by[6][6], bg[6][6];struct V{    char a[6][6];};vector<V> arr;int cnt = 0;void add(){    V v;    for (int i = 0; i < 6; i++)    for (int j = 0; j < 6; j++)        v.a[i][j] = ans[i][j];    arr.push_back(v);}void dfs(int x, int y){    //if(cnt++ == 20) exit(250);    //print(ans);    if (ans[x][y] != '*') {        y++;        if (y == 6) x++, y = 0;        if (x == 6) add();        else dfs(x, y);        return;    }    for (auto it = bx[x].begin(); it != bx[x].end(); it++) {        char t = *it;        int tt = t - 'A';        if (by[y][tt] || bg[g[x][y]][tt]) continue;        ans[x][y] = t;        by[y][tt] = true;        bg[g[x][y]][tt] = true;        it = bx[x].erase(it);        int xx = x, yy = y + 1;        if (yy == 6) xx++, yy = 0;        if (xx == 6) add();        else dfs(xx, yy);        ans[x][y] = '*';        by[y][tt] = false;        bg[g[x][y]][tt] = false;        it = bx[x].insert(it, t);    }}int main(){    //freopen("in", "r", stdin);    for (int i = 0; i < 6; i++) {        for (int j = 0; j < 6; j++) scanf("%c", &g[i][j]);        scanf("\n");    }    int n;    scanf("%d\n", &n);    for (int i = 0; i < 6; i++)        for (char ch = 'A'; ch <= 'F'; ch++) bx[i].push_back(ch);    memset(ans, '*', sizeof(ans));    while (n--) {        char s[3];        scanf("%s\n", s);        int x = s[0] - '0', y = s[1] - '0';        ans[x][y] = s[2];        bx[x].remove(s[2]);        by[y][s[2] - 'A'] = true;        bg[g[x][y]][s[2] - 'A'] = true;    }    dfs(0, 0);    for (int k = 0; k < arr.size(); k++) {        cout << k + 1 << endl;        for (int i = 0; i < 6; i++) {            cout << arr[k].a[i][0];            for (int j = 1; j < 6; j++) {                cout << ' ' << arr[k].a[i][j];            }            cout << endl;        }    }}

由于限制非常多,大量被减枝,实际是运行很快

0 0