├── .gitattributes ├── CS1705-U201714726-王明明-1 ├── U201714726_王明明_CS1705_实验1.c ├── U201714726_王明明_CS1705_实验1.docx ├── U201714726_王明明_CS1705_实验1.exe ├── null └── sss ├── CS1705-U201714726王明明-2 ├── CS1705-U201714726王明明-2.c ├── CS1705-U201714726王明明-2.docx ├── CS1705-U201714726王明明-2.exe ├── null └── sss ├── CS1705-U201714726王明明-3 ├── CS1705-U201714726王明明-3.cpp ├── CS1705-U201714726王明明-3.docx ├── CS1705-U201714726王明明-3.exe └── zzzh ├── CS1705-U201714726王明明-4 ├── CS1705-U201714726王明明-4.cpp ├── CS1705-U201714726王明明-4.exe ├── CS1705-U201714726王明明.docx └── zzzh ├── MySatSolve ├── Game.c ├── MySatSolve.cbp ├── MySatSolve.depend ├── MySatSolve.layout ├── SAT.h ├── Sudoku.h ├── bin │ └── Debug │ │ └── MySatSolve.exe ├── main.c ├── obj │ └── Debug │ │ ├── Game.o │ │ ├── main.o │ │ ├── satSolve.o │ │ └── satSolvePro.o ├── satSolve.c └── satSolvePro.c ├── README.md ├── 数据结构课程设计报告.docx ├── 程序设计综合课程设计任务及指导学生包.rar ├── 课程设计最终提交版本 ├── CS1705-U201714726王明明.docx ├── CS1705-U201714726王明明.exe ├── Game.c ├── SAT.h ├── Sudoku.h ├── main.c ├── satSolve.c ├── sudoku_rule.txt └── 操作手册.docx └── 资料.zip /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /CS1705-U201714726-王明明-1/U201714726_王明明_CS1705_实验1.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726-王明明-1/U201714726_王明明_CS1705_实验1.c -------------------------------------------------------------------------------- /CS1705-U201714726-王明明-1/U201714726_王明明_CS1705_实验1.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726-王明明-1/U201714726_王明明_CS1705_实验1.docx -------------------------------------------------------------------------------- /CS1705-U201714726-王明明-1/U201714726_王明明_CS1705_实验1.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726-王明明-1/U201714726_王明明_CS1705_实验1.exe -------------------------------------------------------------------------------- /CS1705-U201714726-王明明-1/null: -------------------------------------------------------------------------------- 1 | 0 100 -------------------------------------------------------------------------------- /CS1705-U201714726-王明明-1/sss: -------------------------------------------------------------------------------- 1 | 9 100 1 2 3 4 5 6 7 8 9 -------------------------------------------------------------------------------- /CS1705-U201714726王明明-2/CS1705-U201714726王明明-2.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-2/CS1705-U201714726王明明-2.c -------------------------------------------------------------------------------- /CS1705-U201714726王明明-2/CS1705-U201714726王明明-2.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-2/CS1705-U201714726王明明-2.docx -------------------------------------------------------------------------------- /CS1705-U201714726王明明-2/CS1705-U201714726王明明-2.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-2/CS1705-U201714726王明明-2.exe -------------------------------------------------------------------------------- /CS1705-U201714726王明明-2/null: -------------------------------------------------------------------------------- 1 | 0 100 -------------------------------------------------------------------------------- /CS1705-U201714726王明明-2/sss: -------------------------------------------------------------------------------- 1 | 9 100 1 2 3 4 5 6 7 8 9 -------------------------------------------------------------------------------- /CS1705-U201714726王明明-3/CS1705-U201714726王明明-3.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-3/CS1705-U201714726王明明-3.cpp -------------------------------------------------------------------------------- /CS1705-U201714726王明明-3/CS1705-U201714726王明明-3.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-3/CS1705-U201714726王明明-3.docx -------------------------------------------------------------------------------- /CS1705-U201714726王明明-3/CS1705-U201714726王明明-3.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-3/CS1705-U201714726王明明-3.exe -------------------------------------------------------------------------------- /CS1705-U201714726王明明-3/zzzh: -------------------------------------------------------------------------------- 1 | 1a2b4d0#0#0#3c5e0#0#6f7g0#0#0# -------------------------------------------------------------------------------- /CS1705-U201714726王明明-4/CS1705-U201714726王明明-4.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-4/CS1705-U201714726王明明-4.cpp -------------------------------------------------------------------------------- /CS1705-U201714726王明明-4/CS1705-U201714726王明明-4.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-4/CS1705-U201714726王明明-4.exe -------------------------------------------------------------------------------- /CS1705-U201714726王明明-4/CS1705-U201714726王明明.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-4/CS1705-U201714726王明明.docx -------------------------------------------------------------------------------- /CS1705-U201714726王明明-4/zzzh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/CS1705-U201714726王明明-4/zzzh -------------------------------------------------------------------------------- /MySatSolve/Game.c: -------------------------------------------------------------------------------- 1 | #ifndef GAME_C_INCLUDED 2 | #define GAME_C_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Sudoku.h" 8 | #include "SAT.h" 9 | /*********************************** 10 | *文件名称:Game.c 11 | *文件描述:数独游戏部分的代码实现 12 | *日 期:2019-2-21 13 | *版 本:V1.0 14 | *@_@||||||||||| 15 | ***********************************/ 16 | 17 | 18 | int Sudoku() { 19 | Clause *S = NULL; 20 | SatAnswer *answer; 21 | FILE *fp; 22 | char filename[100]; 23 | Var_watch var_watch[MaxNumVar + 1]; 24 | int branchDecision[2 * MaxNumVar + 1]; 25 | int sudokuTable[9][9]; 26 | int op = 1; 27 | clock_t start, finish; 28 | double duration; 29 | srand((unsigned) time(NULL)); 30 | while (op) { 31 | printf("\n\n"); 32 | printf("\t\t\t Sudoku\n"); 33 | printf("\t\t************************************\n"); 34 | printf("\t\t\t1. Generate Sudoku 2. Solve Sudoku\n"); 35 | printf("\t\t\t0. Back\n"); 36 | printf("\t\t************************************\n"); 37 | printf("\t\t\tPlease choose your operation[0--2]:"); 38 | scanf("%d", &op); 39 | system("cls"); 40 | switch (op) { 41 | case 1: 42 | start = clock(); 43 | NewSudoku(&S, &answer, var_watch, branchDecision, sudokuTable); 44 | finish = clock(); 45 | duration = (double) (finish - start) / 1000.0; 46 | printf("The time to generate Sudoku is %.3f s\n", duration); 47 | break; 48 | case 2: 49 | InitSat(&S, &answer, var_watch, branchDecision); 50 | /*printf("Input the file path:\n"); 51 | scanf("%s", filename); 52 | fp = fopen(filename, "r");*/ 53 | fp = fopen("D:\\sudoku_rule.txt", "r"); 54 | LoadCnf(&S, answer, var_watch, fp); 55 | fclose(fp); 56 | start = clock(); 57 | SolveSudoku(answer, var_watch, branchDecision, sudokuTable); 58 | finish = clock(); 59 | duration = (double) (finish - start) / 1000.0; 60 | printf("The time to solve Sudoku is %.3f s\n", duration); 61 | break; 62 | case 0: 63 | return 0; 64 | default: 65 | printf("\t\t\tPlease choose your operation again[0~2]:"); 66 | scanf("%d", &op); 67 | } 68 | } 69 | } 70 | 71 | int NewSudoku(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]) { 72 | clock_t a, b; 73 | double d; 74 | a = clock(); 75 | if (GenerateSudoku(S, answer, var_watch, branchDecision) == 0) 76 | return 0; 77 | b = clock(); 78 | d = (double) (b - a) / 1000.0; 79 | printf("The time to generate the final Sudoku is %.3f s\n\n", d); 80 | DigHole(*answer, var_watch, branchDecision, sudokuTable); 81 | } 82 | 83 | int GenerateSudoku(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[]) { 84 | int x, y, z, i, j, k, l; 85 | int dig_order[82], index; 86 | FILE *fp; 87 | fp = fopen("D:\\sudoku_rule.txt", "w"); 88 | fprintf(fp, "p cnf 729 10287\r\n"); 89 | for (x = 0; x < 9; ++x) 90 | for (y = 0; y < 9; ++y) 91 | for (z = 1; z <= 8; ++z) { 92 | for (i = z + 1; i <= 9; ++i) 93 | fprintf(fp, "%d %d 0\r\n", -(81 * x + 9 * y + z), -(81 * x + 9 * y + i));//每个位置,数字1~9至多出现一次 94 | } 95 | for (x = 0; x < 9; ++x) 96 | for (z = 1; z <= 9; ++z) 97 | for (y = 0; y < 8; ++y) { 98 | for (i = y + 1; i < 9; ++i) 99 | fprintf(fp, "%d %d 0\r\n", -(81 * x + 9 * y + z), -(81 * x + 9 * i + z));//每一行,数字1~9至多出现一次 100 | } 101 | for (y = 0; y < 9; ++y) 102 | for (z = 1; z <= 9; ++z) 103 | for (x = 0; x < 8; ++x) { 104 | for (i = x + 1; i < 9; ++i) 105 | fprintf(fp, "%d %d 0\r\n", -(81 * x + 9 * y + z), -(81 * i + 9 * y + z));//每一列,数字1~9至多出现一次 106 | } 107 | for (z = 1; z <= 9; ++z) 108 | for (i = 0; i < 3; ++i) 109 | for (j = 0; j < 3; ++j) { 110 | for (x = 0; x < 3; ++x) 111 | for (y = 0; y < 3; ++y) 112 | fprintf(fp, "%d ", 81 * (3 * i + x) + 9 * (3 * j + y) + z);//数字1~9在每个3×3数独中至少出现一次 113 | fprintf(fp, "0\r\n"); 114 | for (x = 0; x < 3; ++x) { 115 | for (y = 0; y < 3; ++y) { 116 | for (k = x + 1; k < 3; ++k) 117 | for (l = 0; l < 3; ++l) 118 | if (l != y) 119 | fprintf(fp, "%d %d 0\r\n", -(81 * (3 * i + x) + 9 * (3 * j + y) + z), 120 | -(81 * (3 * i + k) + 9 * (3 * j + l) + z));//数字1~9在每个3×3数独中至多出现一次 121 | } 122 | } 123 | } 124 | fclose(fp); 125 | do { 126 | fp = fopen("D:\\sudoku_rule.txt", "r"); 127 | // fp = fopen("C:\\Users\\dell\\Desktop\\base.txt", "r"); 128 | if (fp == NULL) { 129 | printf("Opening \"D:\\sudoku_rule.txt\" failed.\n "); 130 | return 0; 131 | } 132 | InitSat(S, answer, var_watch, branchDecision); 133 | LoadCnf(S, *answer, var_watch, fp); 134 | fclose(fp); 135 | for (j = 1; j <= 81; ++j) 136 | dig_order[j] = j; 137 | for (j = 81; j > 1; --j) { //随机生成初始化顺序 138 | index = rand() % j + 1; 139 | if (j != index) { 140 | dig_order[j] = dig_order[j] ^ dig_order[index]; 141 | dig_order[index] = dig_order[index] ^ dig_order[j]; 142 | dig_order[j] = dig_order[j] ^ dig_order[index]; 143 | } 144 | } 145 | for (k = 0; k < 11;) { //在棋盘中随机选11个格子随机填入1~9 146 | x = (dig_order[j] - 1) / 9; 147 | y = (dig_order[j] - 1) % 9; 148 | z = rand() % 9 + 1; 149 | for (l = 1; l <= 9; ++l) 150 | if (l == z) 151 | (*answer)->value[81 * x + 9 * y + l] = TRUE; 152 | else 153 | (*answer)->value[81 * x + 9 * y + l] = FALSE; 154 | ++k; 155 | } 156 | knownVar = k; 157 | } while (DPLL(*answer, var_watch, branchDecision, 2, -(rand() % 729 + 1)) == UNSATISFIABLE); 158 | return 1; 159 | } 160 | 161 | int DigHole(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]) { 162 | int x, y, z, i, j, k; 163 | int dig_order[82], index, dig = 1; 164 | int firstBranch; 165 | FILE *fp; 166 | clock_t a, b; 167 | a = clock(); 168 | for (i = 1; i <= numVar; ++i) { 169 | answer->branchLevel[i] = 0; 170 | answer->searched[i] = 0; 171 | answer->singleClause[i] = 0; 172 | } 173 | for (x = 0; x < 9; ++x) { //得到终盘结果 174 | for (y = 0; y < 9; ++y) { 175 | for (z = 1; z <= 9; ++z) 176 | if (answer->value[81 * x + 9 * y + z] == TRUE) { 177 | sudokuTable[x][y] = z; 178 | break; 179 | } 180 | } 181 | } 182 | for (j = 1; j <= 81; ++j) 183 | dig_order[j] = j; 184 | for (j = 81; j > 1; --j) { //随机生成挖洞顺序 185 | index = rand() % j + 1; 186 | if (j != index) { 187 | dig_order[j] = dig_order[j] ^ dig_order[index]; 188 | dig_order[index] = dig_order[index] ^ dig_order[j]; 189 | dig_order[j] = dig_order[j] ^ dig_order[index]; 190 | } 191 | } 192 | for (j = 1; j <= 81 - PreassignVar && dig <= 81;) { 193 | b = clock(); 194 | printf("digged = %d digging = %d time = %.3f s\n", j - 1, dig, (double) (b - a) / 1000.0); 195 | dig_watch(sudokuTable); 196 | x = (dig_order[dig] - 1) / 9; 197 | y = (dig_order[dig++] - 1) % 9; 198 | z = sudokuTable[x][y]; 199 | if (z <= 0) //该位置不可挖,寻找下一个位置 200 | continue; 201 | knownVar = 9 * (81 - j); //已经挖掉j个洞 202 | numBranch = 0; 203 | for (i = 1; i <= 9; ++i) //挖去该位置 204 | answer->value[81 * x + 9 * y + i] = UNKNOWN; 205 | if (j < 4) { //挖去个数小于4,解必定唯一 206 | ++j; 207 | sudokuTable[x][y] = 0; 208 | for (k = 1; k <= 9; ++k) //挖去该位置 209 | answer->value[81 * x + 9 * y + k] = UNKNOWN; 210 | continue; 211 | } 212 | for (i = 1; i <= 9; ++i) { //检测挖去该位置解是否唯一 213 | if (i == z) 214 | continue; 215 | firstBranch = 81 * x + 9 * y + i; 216 | answer->searched[81 * x + 9 * y + i] = 1; //锁定i的另一分支 217 | if (DPLL(answer, var_watch, branchDecision, 2, firstBranch) == SATISFIABLE) //挖去该位置有其他解 218 | break; 219 | knownVar = 9 * (81 - j); //已经挖掉j个洞 220 | numBranch = 0; 221 | for (k = 1; k <= numVar; ++k) { //重置终盘 222 | if (!answer->branchLevel[k]) //决策级为0,为初始化条件,不重置 223 | continue; 224 | answer->value[k] = UNKNOWN; 225 | answer->branchLevel[k] = 0; 226 | answer->searched[k] = 0; 227 | answer->singleClause[k] = 0; 228 | } 229 | } 230 | if (i == 10) { //挖去该位置解仍唯一 231 | ++j; 232 | sudokuTable[x][y] = 0; 233 | } else { //挖去该位置解不唯一 234 | if (dig > 81) 235 | break; 236 | sudokuTable[x][y] = -sudokuTable[x][y]; //该位置不可挖去 237 | for (k = 1; k <= numVar; ++k) { //重置终盘 238 | if (!answer->branchLevel[k]) //决策级为0,为初始化条件,不重置 239 | continue; 240 | answer->value[k] = UNKNOWN; 241 | answer->branchLevel[k] = 0; 242 | answer->searched[k] = 0; 243 | answer->singleClause[k] = 0; 244 | } 245 | for (k = 1; k <= 9; ++k) //填入原来的数 246 | if (k == z) 247 | answer->value[81 * x + 9 * y + k] = TRUE; 248 | else 249 | answer->value[81 * x + 9 * y + k] = FALSE; 250 | } 251 | } 252 | fp = fopen("D:\\sudokuTable.txt", "a+"); 253 | printf("The new Sudoku was generated at \"D:\\sudokuTable.txt\"\n"); 254 | printf("%d known positions:\n", 81 - j + 1); 255 | for (x = 0; x < 9; ++x) { //得到生成数独 256 | for (y = 0; y < 9; ++y) { 257 | sudokuTable[x][y] = abs(sudokuTable[x][y]); 258 | if (sudokuTable[x][y] != 0) { 259 | for (i = 1; i <= 9; ++i) { 260 | if (i != sudokuTable[x][y]) 261 | fprintf(fp, "%d 0\r\n", -(81 * x + 9 * y + i)); 262 | else 263 | fprintf(fp, "%d 0\r\n", 81 * x + 9 * y + i); 264 | } 265 | } 266 | if (y != 0 && y % 3 == 0) 267 | printf("| "); 268 | printf("%d ", sudokuTable[x][y]); 269 | } 270 | printf("\n"); 271 | if (x != 8 && x % 3 == 2) 272 | printf("---------------------\n"); 273 | } 274 | fclose(fp); 275 | } 276 | 277 | int SolveSudoku(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]) { 278 | int x, y, z; 279 | FILE *fp; 280 | DPLL(answer, var_watch, branchDecision, 1, 1); 281 | for (x = 0; x < 9; ++x) { //得到终盘结果 282 | for (y = 0; y < 9; ++y) { 283 | for (z = 1; z <= 9; ++z) 284 | if (answer->value[81 * x + 9 * y + z] == TRUE) { 285 | sudokuTable[x][y] = z; 286 | break; 287 | } 288 | } 289 | } 290 | fp = fopen("D:\\sudokuAnswer.txt", "w"); 291 | printf("The answer to Sudoku was saved at \"D:\\sudokuAnswer.txt\"\n"); 292 | for (x = 0; x < 9; ++x) { //保存并打印数独答案 293 | for (y = 0; y < 9; ++y) { 294 | sudokuTable[x][y] = abs(sudokuTable[x][y]); 295 | if (sudokuTable[x][y] != 0) { 296 | for (int i = 1; i <= 9; ++i) { 297 | if (i != sudokuTable[x][y]) 298 | fprintf(fp, "%d 0\r\n", -(81 * x + 9 * y + i)); 299 | else 300 | fprintf(fp, "%d 0\r\n", 81 * x + 9 * y + i); 301 | } 302 | } 303 | if (y != 0 && y % 3 == 0) 304 | printf("| "); 305 | printf("%d ", sudokuTable[x][y]); 306 | } 307 | printf("\n"); 308 | if (x != 8 && x % 3 == 2) 309 | printf("---------------------\n"); 310 | } 311 | fclose(fp); 312 | } 313 | int dig_watch(int sudokuTable[9][9]) { 314 | int x, y; 315 | for (x = 0; x < 9; ++x) { //保存并打印数独答案 316 | for (y = 0; y < 9; ++y) { 317 | printf("%2d ", sudokuTable[x][y]); 318 | } 319 | printf("\n"); 320 | } 321 | printf("\n\n"); 322 | } 323 | 324 | int dig_test(Clause **S, SatAnswer **answer, Var_watch *var_watch, int *branchDecision) { 325 | FILE *fp; 326 | Clause *S1 = NULL; 327 | Var_watch var_watch1[MaxNumVar + 1]; 328 | int branchDecision1[2 * MaxNumVar + 1]; 329 | int sudokuTable[9][9]; 330 | InitSat(S, answer, var_watch, branchDecision); 331 | fp = fopen("C:\\Users\\dell\\Desktop\\sudoku_rule.txt", "r"); //初始棋盘 332 | LoadCnf(S, *answer, var_watch, fp); 333 | fclose(fp); 334 | InitSat(&S1, answer, var_watch1, branchDecision1); 335 | fp = fopen("D:\\sudoku_answer.txt", "r"); //测试终盘 336 | LoadCnf(&S1, *answer, var_watch1, fp); 337 | fclose(fp); 338 | DigHole(*answer, var_watch, branchDecision, sudokuTable); 339 | } 340 | 341 | 342 | #endif // GAME_C_INCLUDED 343 | -------------------------------------------------------------------------------- /MySatSolve/MySatSolve.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 51 | 52 | -------------------------------------------------------------------------------- /MySatSolve/MySatSolve.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1551165218 source:d:\codeblocks\c\mysatsolve\game.c 3 | 4 | 5 | 6 | "Sudoku.h" 7 | "SAT.h" 8 | 9 | 1551101678 source:d:\codeblocks\c\mysatsolve\satsolvepro.c 10 | 11 | 12 | 13 | 14 | 15 | 16 | 1551170736 source:d:\codeblocks\c\mysatsolve\satsolve.c 17 | 18 | 19 | 20 | "SAT.h" 21 | 22 | 1551165218 d:\codeblocks\c\mysatsolve\sat.h 23 | 24 | 1551165218 source:d:\codeblocks\c\mysatsolve\main.c 25 | 26 | 27 | 28 | 29 | "SAT.h" 30 | "Sudoku.h" 31 | 32 | 1551165218 d:\codeblocks\c\mysatsolve\sudoku.h 33 | "SAT.h" 34 | 35 | -------------------------------------------------------------------------------- /MySatSolve/MySatSolve.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /MySatSolve/SAT.h: -------------------------------------------------------------------------------- 1 | #ifndef SAT_H_INCLUDED 2 | #define SAT_H_INCLUDED 3 | 4 | #define MaxNumVar 4000 5 | #define PreassignVar 18 6 | //预先分配的变元数目 7 | #define CONFLICT 0 8 | #define SATISFIABLE 1 9 | #define UNSATISFIABLE 0 10 | #define OTHERS 2 11 | 12 | #define SINGLE -1 13 | 14 | //UNKNOWN表示该变元未知,NONE表示该变元不存在,FALSE表示该变元为假,TRUE表示该变元为真 15 | #define FALSE -1 16 | #define TRUE 1 17 | #define UNKNOWN 0 18 | #define NONE 2 19 | /*********************************** 20 | *文件名称:SAT.h 21 | *文件描述:关于求解SAT问题的函数声明、数据结构定义 22 | *日 期:2019-2-21 23 | *版 本:V1.0 24 | *@_@||||||||||| 25 | ***********************************/ 26 | 27 | //该结构参考双文字监视方法,可看作两张表格 28 | typedef struct varWatch { 29 | struct varList *pos; //文字邻接表,正文字邻接表,负文字邻接表, 30 | struct varList *neg; 31 | } Var_watch; 32 | 33 | typedef struct varList { 34 | struct clause *p; //指向一个子句 35 | struct varList *next; //指向下一个包含该文字的子句 36 | } VarList; 37 | 38 | typedef struct clause { 39 | struct clauseLiteral *p;//指向一个子句中的下一个文字 40 | struct clause *nextClause;//这个在邻接表中无意义,要从读取CNF文件时看出效果 41 | } Clause; 42 | 43 | typedef struct clauseLiteral { 44 | int data;//文字的值 45 | struct clauseLiteral *next; //指向子句中的下一个文字 46 | } ClauseLiteral; 47 | 48 | typedef struct satAnswer { 49 | int branchLevel[MaxNumVar + 1]; //赋值时的决策树高度 50 | int value[MaxNumVar + 1]; //TRUE or FALSE or UNKNOWN or NONE 51 | int searched[MaxNumVar + 1]; //已被搜索的情况数 52 | int singleClause[MaxNumVar + 1]; //标记是否存在该变量的单子句 53 | } SatAnswer; 54 | 55 | int InitSat(Clause **S, SatAnswer **answer, Var_watch *var_watch, int *branchDecision); 56 | 57 | int Sat(); 58 | 59 | int LoadCnf(Clause **S, SatAnswer *answer, Var_watch var_watch[], FILE *fp); 60 | 61 | int GetNum(FILE *fp); 62 | 63 | int DPLL(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int op, int firstBranch); 64 | 65 | int PrintAnswer(SatAnswer *answer, int result, char filename[100], int duration); 66 | 67 | int PutClause(Clause *ctemp, int var, Var_watch var_watch[]); 68 | 69 | int Deduce(int blevel, SatAnswer *answer, Var_watch var_watch[], int branchDecision[], VarList *root); 70 | 71 | int SingleClauseDeduce(int blevel, SatAnswer *answer, Var_watch var_watch[], int branchDecision[], VarList **vp); 72 | 73 | int NextBranch(int branchDecision[], SatAnswer *answer); 74 | 75 | int Analyse_conflict(int *blevel, int var, SatAnswer *answer); 76 | 77 | int ChectAnswer(Clause *S, SatAnswer *answer); 78 | 79 | int numVar; 80 | int knownVar; 81 | int numBranch; 82 | int firstBranch[MaxNumVar]; 83 | 84 | #endif // SAT_H_INCLUDED 85 | -------------------------------------------------------------------------------- /MySatSolve/Sudoku.h: -------------------------------------------------------------------------------- 1 | #ifndef SUDOKU_H_INCLUDED 2 | #define SUDOKU_H_INCLUDED 3 | #include "SAT.h" 4 | /*********************************** 5 | *文件名称:Sudoku.h 6 | *文件描述:用来定义数独游戏相关的函数 7 | *日 期:2019-2-21 8 | *版 本:V1.0 9 | *@_@||||||||||| 10 | ***********************************/ 11 | 12 | 13 | int Sudoku(); 14 | 15 | int NewSudoku(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]); 16 | 17 | int GenerateSudoku(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[]); 18 | 19 | int DigHole(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]); 20 | 21 | int SolveSudoku(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]); 22 | int dig_watch(int sudokuTable[9][9]); 23 | int dig_test(Clause **S, SatAnswer **answer, Var_watch *var_watch, int *branchDecision); 24 | 25 | 26 | #endif // SUDOKU_H_INCLUDED 27 | -------------------------------------------------------------------------------- /MySatSolve/bin/Debug/MySatSolve.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/MySatSolve/bin/Debug/MySatSolve.exe -------------------------------------------------------------------------------- /MySatSolve/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "SAT.h" 6 | #include "Sudoku.h" 7 | /*********************************** 8 | *文件名称:main.c 9 | *文件描述:主界面的显示、函数调用 10 | *日 期:2019-2-21 11 | *版 本:V1.0 12 | *@_@||||||||||| 13 | ***********************************/ 14 | 15 | 16 | int main() { 17 | int op = 1; 18 | while (op) { 19 | printf("\n\n"); 20 | printf("\t\t\t Main Menu \n"); 21 | printf("\t\t************************************\n"); 22 | printf("\t\t\t1. Sudoku 2. SAT\n"); 23 | printf("\t\t\t0. Exit\n"); 24 | printf("\t\t************************************\n"); 25 | printf("\t\t\tPlease choose your operation[0--2]:"); 26 | scanf("%d", &op); 27 | system("cls"); 28 | switch (op) { 29 | case 1: 30 | Sudoku(); 31 | break; 32 | case 2: 33 | Sat(); 34 | break; 35 | case 0: 36 | exit(0); 37 | default: 38 | printf("\t\t\tPlease choose your operation again[0--2]:"); 39 | scanf("%d", &op); 40 | } 41 | } 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /MySatSolve/obj/Debug/Game.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/MySatSolve/obj/Debug/Game.o -------------------------------------------------------------------------------- /MySatSolve/obj/Debug/main.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/MySatSolve/obj/Debug/main.o -------------------------------------------------------------------------------- /MySatSolve/obj/Debug/satSolve.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/MySatSolve/obj/Debug/satSolve.o -------------------------------------------------------------------------------- /MySatSolve/obj/Debug/satSolvePro.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/MySatSolve/obj/Debug/satSolvePro.o -------------------------------------------------------------------------------- /MySatSolve/satSolve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "SAT.h" 5 | /*********************************** 6 | *文件名称:satSolve.c 7 | *文件描述:解决SAT问题的函数实现 8 | *日 期:2019-2-21 9 | *版 本:V1.0 10 | *@_@||||||||||| 11 | ***********************************/ 12 | 13 | int InitSat(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[]) { 14 | Clause *cfront = *S, *crear; //子句的前后指针,用于清空 15 | ClauseLiteral *lfront, *lrear; //文字的前后指针 16 | //子句初始化 17 | while (cfront) { 18 | crear = cfront->nextClause; //这两行可以理解为一个表格从左上角出发 19 | lfront = cfront->p; 20 | while (lfront) { 21 | lrear = lfront->next; 22 | free(lfront); 23 | lfront = lrear; //逐一清空子句中的文字,清空表格中的一行 24 | } 25 | free(cfront); 26 | cfront = crear; //清除完毕之后,由于free了前指针。。。 27 | } 28 | *S = NULL; 29 | //解初始化 30 | numVar = 0; //变元数目为0 31 | knownVar = 0; //已知变元数目为0 32 | numBranch = 0; //分支数目为0 33 | *answer = (SatAnswer *) malloc(sizeof(SatAnswer)); //给answer结构分配空间 34 | for (int i = 1; i <= MaxNumVar; ++i) { 35 | //解初始化 36 | (*answer)->value[i] = NONE; //表示变元不存在 37 | (*answer)->branchLevel[i] = 0; //赋值时决策树高度为0 38 | (*answer)->searched[i] = 0; //已被搜索的情况数是0 39 | (*answer)->singleClause[i] = 0; //该变量的单子句数目为0 40 | //文字邻接表初始化 41 | var_watch[i].pos = (VarList *) malloc(sizeof(VarList)); //为正文字邻接表指针分配空间 42 | var_watch[i].pos->next = NULL; //正文字邻接表指针指向空 43 | var_watch[i].neg = (VarList *) malloc(sizeof(VarList)); //为负文字邻接表指针分配空间 44 | var_watch[i].neg->next = NULL; //负文字邻接表指针指向空 45 | } 46 | //分支决策计数器初始化 47 | for (int j = 1; j <= 2 * MaxNumVar; ++j) 48 | branchDecision[j] = 0; //分支决策计数器初始化为0 49 | } 50 | 51 | int Sat() { 52 | Clause *S = NULL; //子句指针 53 | SatAnswer *answer; //SAT解的指针 54 | Var_watch var_watch[MaxNumVar + 1]; //最大变元数目加一个空间 55 | FILE *fp; //文件指针 56 | char filename[100]; //文件名 57 | int branchDecision[2 * MaxNumVar + 1]; //决策树最大分支 应该是变元数目的二倍加一(一个变元有两种可能) 58 | int op = 1,result; 59 | clock_t start, finish; //调用的time.h头文件 60 | int duration; //用于表示耗时 61 | while (op) { 62 | printf("\n\n"); 63 | printf("\t\t\t\t SAT\n"); 64 | printf("\t\t\t******************************************\n"); 65 | printf("\t\t\t1. New SAT 2. Check Answer\n"); 66 | printf("\t\t\t0. Back\n"); 67 | printf("\t\t\t******************************************\n"); 68 | printf("\t\t\tPlease choose your operation[0--2]:"); 69 | scanf("%d", &op); 70 | system("cls"); 71 | switch (op) { 72 | case 1://case1意味着要读取cnf文件,首先要初始化,因此有下一行 73 | InitSat(&S, &answer, var_watch, branchDecision); 74 | printf("Please input the file path:\n"); 75 | scanf("%s", filename); 76 | fp = fopen(filename, "r"); 77 | 78 | if (fp == NULL) { 79 | printf("fail to open the file!\n "); 80 | break; 81 | } else LoadCnf(&S, answer, var_watch, fp); //调用LoadCnf 函数,读取文件 82 | start = clock(); //调用time.h,记录开始时间 83 | result = DPLL(answer, var_watch, branchDecision, 1, 1); 84 | finish = clock(); //调用time.h,记录结束时间 85 | duration = (finish - start);//得到解决问题的耗时 86 | if (result == SATISFIABLE) 87 | { 88 | printf("Time to solve the SAT problem %d ms\n", duration); 89 | PrintAnswer(answer, 1, filename, duration); 90 | } 91 | else 92 | { 93 | printf("No solution!\n"); 94 | PrintAnswer(answer, 0, filename, duration); 95 | } 96 | break; 97 | case 2: 98 | ChectAnswer(S, answer); 99 | break; 100 | case 0: 101 | return 0; 102 | default: 103 | printf("\t\t\tPlease choose your operation again[0~2]:"); 104 | scanf("%d", &op); 105 | } 106 | } 107 | } 108 | 109 | int LoadCnf(Clause **S, SatAnswer *answer, Var_watch var_watch[], FILE *fp) {//加载CNF文件 110 | char c; 111 | Clause *ctemp, *cp = NULL; //两个指针,加载CNF文件中的子句会用到 112 | ClauseLiteral *lp, *ltemp; //两个指针,加载CNF文件中的文字会用到 113 | int var; //变量的值 114 | int numClauseVar; //每个子句的变元数 115 | fscanf(fp, "%c", &c); 116 | while (c == 'c') { //注释段 117 | while (c != '\n' && c != '\r') // 118 | fscanf(fp, "%c", &c); // 119 | fscanf(fp, "%c", &c); 120 | if (c == '\n') //如果读取到换行符,意味着要再重复一次 121 | fscanf(fp, "%c", &c); 122 | } 123 | fscanf(fp, " cnf "); //开始读到文件的信息段 124 | numVar = GetNum(fp); //读取变量数,并赋值给numVar 125 | GetNum(fp); //读取子句数 126 | var = GetNum(fp); //再次调用,读取下一行第一个变量值,把值赋给var 127 | while (1) { 128 | numClauseVar = 0; 129 | ctemp = (Clause *) malloc(sizeof(Clause)); //为ctemp指针分配空间 130 | lp = ctemp->p; //lp为文字指针,,可以想象一下表格长什么样 131 | while (var) { 132 | ++numClauseVar; //计数器功能,统计每个子句的变元数目 133 | if (answer->value[abs(var)] == NONE) 134 | answer->value[abs(var)] = UNKNOWN; 135 | ltemp = (ClauseLiteral *) malloc(sizeof(ClauseLiteral)); 136 | ltemp->data = var; //文字的值域改成var,赋值 137 | ltemp->next = NULL; // 138 | if (numClauseVar == 1) { //储存子句中首个变量 139 | ctemp->p = lp = ltemp; 140 | } else { //储存子句中非首个变量 141 | lp->next = ltemp; 142 | lp = lp->next; 143 | } 144 | if (var > 0) 145 | ++firstBranch[var]; //初始分支决策计数增加 146 | else 147 | ++firstBranch[numVar - var]; 148 | PutClause(ctemp, var, var_watch); //储存各变量的子句地址 149 | var = GetNum(fp); 150 | } 151 | if (numClauseVar == 1) { //输入单子句,则该子句必须满足,无需存入 152 | answer->value[abs(lp->data)] = lp->data / abs(lp->data); 153 | ++knownVar; //已知变元数目加1 154 | } else if (*S == NULL) { 155 | *S = cp = ctemp; 156 | cp->nextClause = NULL; 157 | } else { //想想表格的形式,是列的头 158 | cp->nextClause = ctemp; 159 | cp = cp->nextClause; 160 | cp->nextClause = NULL; 161 | } 162 | var = GetNum(fp); //若到达文件尾,再执行一次z'z 读文件操作时,设置文件结束标志 163 | if (feof(fp)) 164 | break; 165 | } 166 | } 167 | 168 | int GetNum(FILE *fp) {//这个函数用来读取cnf文件时得到变量数、子句数、后面的内容 169 | char c; 170 | int sign = 1, num = 0; //num 用来得到文字的值,sign用来标记文字是正或者负 171 | fscanf(fp, "%c", &c); 172 | if (c == '-') { 173 | sign = -1; //sign变为-1,表示为负文字 174 | fscanf(fp, "%c", &c); 175 | } else if (c == '0') { //表示该条子句结束 176 | fscanf(fp, "%c", &c); 177 | if (c == '\r') //表示换行 178 | fscanf(fp, "%c", &c); 179 | return num; // 180 | } else if (feof(fp)) //如果是结束标记 181 | return 0; 182 | while (c != ' ' && c != '\n' && c != '\r') { 183 | num = num * 10 + c - '0'; //得到文字的值 184 | fscanf(fp, "%c", &c); 185 | } 186 | if (c == '\r') 187 | fscanf(fp, "%c", &c); 188 | return sign * num; //用来得到文字(包括正负和值) 189 | } 190 | 191 | int DPLL(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int op, int firstBranch) { 192 | int status, var, blevel = 0; //初始判定级为0 193 | VarList *vp; //邻接表指针,用于 194 | while (1) { 195 | if (numBranch++ == 0) { //第一次分支决策 196 | if (op == 1) //1:SAT求解、2:生成数独的检验求解 197 | var = NextBranch(branchDecision, answer); 198 | else 199 | var = firstBranch; 200 | } else 201 | var = NextBranch(branchDecision, answer); //下一分支决策 202 | ++blevel; //判定级加1 203 | answer->value[abs(var)] = var / abs(var); //进入一分支 204 | answer->branchLevel[abs(var)] = blevel; 205 | ++answer->searched[abs(var)]; //已被搜索情况数加1 206 | ++knownVar; //已知变元数目加1 207 | while (1) { 208 | if (var > 0) 209 | vp = var_watch[var].neg->next; //var为TRUE,则搜索var为FALSE的子句 210 | else 211 | vp = var_watch[-var].pos->next; //var为FALSE,则搜索var为TRUE的子句 212 | status = Deduce(blevel, answer, var_watch, branchDecision, vp);//单子句传播,返回子句的状态 213 | if (status == SATISFIABLE) //满足的情况 214 | return SATISFIABLE; 215 | else if (status == CONFLICT) { 216 | var = Analyse_conflict(&blevel, var, answer);//var > 0,矛盾,开始回溯 217 | if (blevel == 0) 218 | return UNSATISFIABLE; 219 | else { //进入另一分支,不满足 220 | answer->value[var] = -answer->value[var];//则值进行反转,正变成负,负变成正 221 | ++answer->searched[var]; //被搜索情况数目加1 222 | if (answer->value[var] < 0) 223 | var = -var; 224 | } 225 | } else if (status == OTHERS) break; //已知条件不足,进入下一层 226 | } 227 | } 228 | } 229 | 230 | int PrintAnswer(SatAnswer *answer,int result, char filename[100], int duration) { 231 | FILE *fp; 232 | fp = filename; 233 | int p = 0; 234 | while (filename[p] != 0) p++; 235 | while (filename[p] != '.') p--; 236 | p++; 237 | filename[p] = 'r'; 238 | p++; 239 | filename[p] = 'e'; 240 | p++; 241 | filename[p] = 's'; 242 | p++; 243 | filename[p] = 0; 244 | fp = fopen(fp, "w"); 245 | if(result == 1) 246 | fprintf(fp, "s 1\r\n"); 247 | else 248 | fprintf(fp, "s 0\r\n"); 249 | fprintf(fp, "v "); 250 | for(int i = 1; i < MaxNumVar; i++) 251 | { 252 | if(answer->value == TRUE) 253 | fprintf(fp, "%d ", i); 254 | else 255 | fprintf(fp, "-%d ", i); 256 | } 257 | fprintf(fp, "\r\n"); 258 | fprintf(fp, "t %d\r\n", duration); 259 | fclose(fp); 260 | printf("The answer has been saved\n"); 261 | printf("One solution of SAT is:\n"); 262 | for (int i = 1; i <= MaxNumVar; ++i) 263 | if (answer->value[i] == TRUE) 264 | { 265 | printf("%d ", i); 266 | //fprintf(file, "%d ", i); 267 | } 268 | else if (answer->value[i] == FALSE) 269 | printf("-%d ", i); 270 | printf("\n"); 271 | 272 | //fflush(file); 273 | 274 | } 275 | 276 | int PutClause(Clause *ctemp, int var, Var_watch var_watch[]) { 277 | VarList *wp; 278 | if (var > 0) //判断var是否大于零,从而归纳到相应的表格中 279 | wp = var_watch[var].pos; 280 | else 281 | wp = var_watch[-var].neg; 282 | while (wp->next) 283 | wp = wp->next; //循环,找到VarList的尾部,将var添加到尾部 284 | wp->next = (VarList *) malloc(sizeof(VarList));//分配空间 285 | wp = wp->next; // 286 | wp->p = ctemp; //将子句放在末尾 287 | wp->next = NULL; 288 | } 289 | 290 | int Deduce(int blevel, SatAnswer *answer, Var_watch var_watch[], int branchDecision[], VarList *root) { 291 | int top = 0, status; //status表示状态 292 | VarList *stack[MaxNumVar], *vp = root; //栈,栈的最大长度为最大变元数目 293 | stack[top++] = vp; 294 | while (top) { 295 | vp = stack[top - 1]; //访问栈顶元素 296 | status = SINGLE; 297 | while (status == SINGLE && vp) { //左子树搜索 298 | status = SingleClauseDeduce(blevel, answer, var_watch, branchDecision, &vp); 299 | stack[top++] = vp; //左孩子入栈 300 | } 301 | --top; //空指针退栈 302 | if (status == CONFLICT) 303 | return CONFLICT; 304 | if (top) { //右子树搜索 305 | vp = stack[--top]; //根节点出栈 306 | if (vp->next) 307 | stack[top++] = vp->next; //右孩子入栈 308 | } 309 | } 310 | if (knownVar < numVar) 311 | return OTHERS; 312 | else return SATISFIABLE; 313 | } 314 | 315 | int SingleClauseDeduce(int blevel, SatAnswer *answer, Var_watch var_watch[], int branchDecision[], VarList **vp) { 316 | Clause *cp; //子句指针 317 | ClauseLiteral *lp; //文字指针 318 | int unknownNum, firstUnknown, satisfiable; // 319 | //初始化 320 | unknownNum = 0; 321 | firstUnknown = 0; 322 | satisfiable = 0; 323 | cp = (*vp)->p; //将cp指向vp所指向的子句 324 | lp = cp->p; //文字指针指向cp所指向的文字 325 | if (lp == NULL) 326 | return OTHERS; 327 | while (lp) { 328 | if (lp->data > 0) 329 | ++branchDecision[lp->data]; //分支决策计数增加 330 | else 331 | ++branchDecision[numVar - lp->data]; 332 | if (answer->value[abs(lp->data)] * lp->data > 0) { //子句中存在值为TRUE的文字,子句成立 333 | satisfiable = 1; 334 | break; 335 | } 336 | if (answer->value[abs(lp->data)] == UNKNOWN) { 337 | ++unknownNum; //计数子句中未被赋值的文字, 338 | if (firstUnknown == 0) 339 | firstUnknown = lp->data; //记录第一个未知的文字 340 | } 341 | lp = lp->next; 342 | } 343 | if (unknownNum == 0 && satisfiable == 0) //该子句文字均已知并且都为FALSE,为矛盾句 344 | return CONFLICT; 345 | else if (unknownNum == 1 && satisfiable == 0) { //该子句无值为TRUE的文字,且只有一个未知文字,为单子句 346 | answer->singleClause[abs(firstUnknown)] = 1; //标记,单子句出现的位置 347 | answer->value[abs(firstUnknown)] = firstUnknown / abs(firstUnknown); 348 | answer->branchLevel[abs(firstUnknown)] = blevel; 349 | ++knownVar; //已被赋值的变元数目加1,即确定变元数目加1 350 | if (firstUnknown > 0) 351 | *vp = var_watch[firstUnknown].neg->next; //var为TRUE,则检索var为FALSE的子句 352 | else 353 | *vp = var_watch[-firstUnknown].pos->next; //var为FALSE,则检索var为TRUE的子句 354 | return SINGLE; 355 | } else if (knownVar < numVar) { 356 | *vp = NULL; 357 | return OTHERS; //判断条件不足,返回OTHERS 358 | } else return SATISFIABLE; 359 | } 360 | 361 | int NextBranch(int branchDecision[], SatAnswer *answer) {//下一分支函数 362 | int maxVar = numVar, maxCount = 0; 363 | int *branch; 364 | ++numBranch; 365 | branch = numBranch == 1 ? firstBranch : branchDecision; 366 | for (int i = 1; i <= 2 * numVar; ++i) { 367 | if (i <= numVar && answer->value[i] != UNKNOWN) 368 | continue; 369 | if (i > numVar && answer->value[i - numVar] != UNKNOWN) 370 | continue; 371 | if (maxCount <= *(branch + i)) { 372 | maxVar = i; 373 | maxCount = *(branch + i); 374 | 375 | } 376 | // maxVar = i; 377 | } 378 | return maxVar > numVar ? numVar - maxVar : maxVar; 379 | } 380 | 381 | int Analyse_conflict(int *blevel, int var, SatAnswer *answer) {//回溯函数 382 | int fore = abs(var); 383 | while (*blevel != 0) { 384 | for (int j = 1; j <= numVar; ++j) 385 | if (j != fore && answer->branchLevel[j] == *blevel) { //将由var赋值产生的单子句重置 386 | answer->value[j] = UNKNOWN; 387 | answer->branchLevel[j] = 0; 388 | answer->searched[j] = 0; 389 | answer->singleClause[j] = 0; 390 | --knownVar; 391 | } 392 | if (*blevel != 1) { 393 | if (answer->searched[fore] == 2) { //var的TRUE和FALSE分支均搜索过,进行回溯 394 | --(*blevel); 395 | answer->value[fore] = UNKNOWN; 396 | answer->branchLevel[fore] = 0; 397 | answer->searched[fore] = 0; 398 | --knownVar; 399 | for (int i = 1; i <= numVar; ++i) 400 | if (answer->branchLevel[i] == *blevel && answer->singleClause[i] == 0) { 401 | fore = i; 402 | break; 403 | } 404 | } else break; //搜索另一分支 405 | } else if (answer->searched[abs(fore)] == 2)//blevel1全部搜索完 406 | --(*blevel); 407 | else break; //搜索blevel1的另一分支 408 | } 409 | return fore; 410 | } 411 | 412 | int ChectAnswer(Clause *S, SatAnswer *answer) {//解的正误检查 413 | FILE *fp; 414 | Clause *cp = S; 415 | VarList *error = NULL, *ep; 416 | ClauseLiteral *lp; 417 | int ok = 0, s = 1, num = 0; 418 | fp = fopen("D:\\Satcheck.txt", "w");//在D盘建立一个txt文件 419 | error = ep = (VarList *) malloc(sizeof(VarList));//分配空间 420 | error->next = NULL; 421 | fprintf(fp, "Answer:\r\n"); 422 | for (int i = 1; i <= MaxNumVar; ++i) 423 | if (answer->value[i] == TRUE)//标记的第i个值为正文字 424 | fprintf(fp, "%d ", i); 425 | else if (answer->value[i] == FALSE)//标记的第i个值为负文字 426 | fprintf(fp, "-%d ", i); 427 | fprintf(fp, "\r\n\r\n"); 428 | while (cp) { 429 | ok = 0; 430 | lp = cp->p; 431 | fprintf(fp, "C%-4d ", ++num); 432 | while (lp) { 433 | fprintf(fp, "%4d ", lp->data); 434 | if (answer->value[abs(lp->data)] * lp->data > 0) 435 | ok = 1; 436 | lp = lp->next; 437 | } 438 | if (ok == 1) 439 | fprintf(fp, "T\r\n"); 440 | else { 441 | s = 0; 442 | fprintf(fp, "F\r\n"); 443 | ep->next = (VarList *) malloc(sizeof(VarList)); 444 | ep = ep->next; 445 | ep->p = cp; 446 | ep->next = NULL; 447 | } 448 | cp = cp->nextClause; 449 | } 450 | if (s == 1) 451 | printf("Check: Satisfiable!\n"); 452 | else printf("Check: Unsatisfiable!\n");//检查的结果 453 | printf("The detail was saved at \"D:\\Satcheck.txt\"\n");//保存在哪里了 454 | ep = error->next; 455 | if (ep) { 456 | fprintf(fp, "\r\n\r\nError:\r\n"); 457 | num = 0; 458 | } 459 | while (ep) { 460 | fprintf(fp, "C%-4d ", ++num); 461 | lp = ep->p->p; 462 | while (lp) { 463 | fprintf(fp, "%4d ", lp->data); 464 | lp = lp->next; 465 | } 466 | fprintf(fp, "F\r\n"); 467 | ep = ep->next; 468 | } 469 | fclose(fp); 470 | } 471 | -------------------------------------------------------------------------------- /MySatSolve/satSolvePro.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | #define TRUETRUE 1 9 | #define FALSE 0 10 | #define OK 1 11 | #define ERROR 0 12 | #define DECIDE 1 13 | #define UNDECIDE 3 14 | #define SUDUPTN 729 15 | #define SUDUCTN 10530 16 | 17 | 18 | typedef int status; 19 | typedef struct LiteralsNode 20 | { 21 | int literals; 22 | int flag; 23 | struct LiteralsNode *next; 24 | } LiteralsNode; //文字结点 25 | 26 | typedef struct ClauseNode 27 | { 28 | int clause; 29 | int trueValue; 30 | int flag; 31 | struct ClauseNode *next; 32 | } ClauseNode; //子句结点 33 | 34 | typedef struct 35 | { 36 | int lNumber; 37 | LiteralsNode *head; 38 | LiteralsNode *Watch1; 39 | LiteralsNode *Watch2; 40 | } ClauseList; //子句邻接表 41 | 42 | typedef struct 43 | { 44 | int cNumber; 45 | ClauseNode *head; 46 | ClauseNode *pos_watched; 47 | ClauseNode *neg_watched; 48 | } LiteralsList; //文字邻接表 49 | 50 | typedef struct 51 | { 52 | LiteralsNode *head; 53 | } Backtree; 54 | typedef struct 55 | { 56 | int totalpNumber; 57 | int totalCNumber; 58 | } TotalNumber; 59 | 60 | typedef struct 61 | { 62 | int *pTV; 63 | int num; 64 | } TrueValue; 65 | 66 | typedef struct 67 | { 68 | status SAT; 69 | int *pTV; 70 | clock_t time; 71 | } Result; 72 | 73 | typedef struct 74 | { 75 | int pos; 76 | int neg; 77 | } Counter; 78 | int SatPro(); 79 | status Save (ClauseList *CL,TotalNumber TN); 80 | int createchain(int pn,int flag,int cn,LiteralsList **LL, ClauseList **CL,Counter **counter); 81 | void sudurestraint (LiteralsList **LL, ClauseList **CL,TotalNumber *TN,Counter **counter); 82 | status Load (LiteralsList **LL, ClauseList **CL,TotalNumber *TN,Counter **counter); 83 | Result DPLLPro (LiteralsList *LL, ClauseList *CL, TotalNumber TN,Counter *counter); 84 | void destroy (TrueValue*); 85 | Result UNSAT (clock_t start); 86 | Result SAT(clock_t start,int *pTV); 87 | void ordercounter(int *order,Counter *counter,int n); 88 | void showCL(ClauseList *CL,int begin,int cn); 89 | void showLL(LiteralsList *LL,int begin,int pn); 90 | void deleteclause(int cn,LiteralsList **LL, ClauseList **CL,TotalNumber *TN,Counter **counter); 91 | 92 | 93 | int SatPro() 94 | { 95 | int i,*pTV,op=1,op1; 96 | LiteralsList *LL=NULL; 97 | ClauseList *CL=NULL; 98 | TotalNumber TN; 99 | LiteralsNode *lp; 100 | ClauseNode *cp; 101 | Counter *counter; 102 | Result result; 103 | while(op) 104 | { 105 | system("cls"); 106 | printf("\n\n"); 107 | printf("\t SUDU & SAT问题求解 \n"); 108 | printf("-----------------------------------------------------\n"); 109 | printf("\tSAT :1 SUDU:2\n"); 110 | printf("\t退出:0\n"); 111 | printf("-----------------------------------------------------"); 112 | printf("\n请选择你要执行的操作:\n"); 113 | 114 | scanf("%d",&op); 115 | if(op==1) 116 | { 117 | 118 | Load(&LL,&CL,&TN,&counter); 119 | result= DPLLPro (LL, CL, TN, counter); 120 | printf("DPLLPro\n"); 121 | if(result.SAT==TRUETRUE) 122 | { 123 | printf("s 1\n"); 124 | for(i=1; i<=TN.totalpNumber; i++) 125 | { 126 | if(result.pTV[i]==FALSE) 127 | printf("-%d ",i); 128 | else 129 | printf("%d ",i); 130 | } 131 | printf("\nt %ld",result.time); 132 | } 133 | else 134 | { 135 | printf("s 0\n"); 136 | printf("t %ld",result.time); 137 | } 138 | } 139 | } 140 | return 0; 141 | } 142 | 143 | 144 | 145 | 146 | status Load (LiteralsList **LL, ClauseList **CL,TotalNumber *TN,Counter **counter) 147 | { 148 | FILE *fp; 149 | char filename[100],s[100],c; 150 | int n,i=1,j,flag,pn; 151 | LiteralsNode *lp,*lp1; 152 | ClauseNode *cp,*cp1; 153 | printf("请输入要载入的文件:"); 154 | scanf("%s",filename); 155 | fp=fopen(filename,"r"); 156 | if(fp==NULL) 157 | { 158 | printf("文件打开失败!"); 159 | return ERROR; 160 | } 161 | fscanf(fp,"%c",&c); 162 | while(c!='p') 163 | { 164 | fgets(s,100,fp); 165 | fscanf(fp,"%c",&c); 166 | } 167 | do 168 | { 169 | fscanf(fp,"%s",s); 170 | } 171 | while(strcmp(s,"cnf")); 172 | fscanf(fp,"%d",&n); 173 | TN->totalpNumber=n; 174 | *LL=(LiteralsList *)malloc((n+1)*sizeof(LiteralsList)); 175 | *counter=(Counter *)malloc((n+1)*sizeof(Counter)); 176 | for(i=0; i<=n; i++) 177 | { 178 | (*LL)[i].cNumber=0; 179 | (*LL)[i].head=NULL; 180 | (*LL)[i].neg_watched=(*LL)[i].pos_watched=NULL; 181 | (*counter)[i].neg=(*counter)[i].pos=0; 182 | } 183 | fscanf(fp,"%d",&n); 184 | TN->totalCNumber=n; 185 | *CL=(ClauseList *)malloc((n+1)*sizeof(ClauseList)); 186 | for(i=0; i<=n; i++) 187 | { 188 | (*CL)[i].lNumber=0; 189 | (*CL)[i].head=NULL; 190 | } 191 | for(i=1; i<=TN->totalCNumber; i++) 192 | { 193 | lp=(*CL)[i].head; 194 | fscanf(fp,"%d",&n); 195 | while(n) 196 | { 197 | flag=n>0?1:0; 198 | pn=n>0?n:-n; 199 | if(flag==1) 200 | ((*counter)[pn]).pos++; 201 | else ((*counter)[pn]).neg++; 202 | lp1=(LiteralsNode *)malloc(sizeof(LiteralsNode)); 203 | lp1->literals=pn; 204 | lp1->flag=flag; 205 | lp1->next=NULL; 206 | if(!lp) 207 | (*CL)[i].head=lp1; 208 | else 209 | lp->next=lp1; 210 | lp=lp1; 211 | (*CL)[i].lNumber++; 212 | cp1=(ClauseNode *)malloc(sizeof(ClauseNode)); 213 | cp1->clause=i; 214 | cp1->trueValue=UNDECIDE; 215 | cp1->flag=flag; 216 | cp1->next=NULL; 217 | if(flag==TRUETRUE) 218 | { 219 | if((*LL)[pn].pos_watched==NULL) 220 | (*LL)[pn].pos_watched=cp1; 221 | else 222 | { 223 | cp=(*LL)[pn].pos_watched; 224 | while(cp->next) 225 | cp=cp->next; 226 | cp->next=cp1; 227 | } 228 | (*counter)[pn].pos++; 229 | } 230 | else 231 | { 232 | if((*LL)[pn].neg_watched==NULL) 233 | (*LL)[pn].neg_watched=cp1; 234 | else 235 | { 236 | cp=(*LL)[pn].neg_watched; 237 | while(cp->next) 238 | cp=cp->next; 239 | cp->next=cp1; 240 | } 241 | (*counter)[pn].neg++; 242 | } 243 | 244 | (*LL)[pn].cNumber++; 245 | fscanf(fp,"%d",&n); 246 | } 247 | 248 | (*CL)[i].Watch1=(*CL)[i].head; 249 | if((*CL)[i].head) 250 | (*CL)[i].Watch2=(*CL)[i].head->next; 251 | else (*CL)[i].Watch2=NULL; 252 | } 253 | fclose(fp); 254 | return OK; 255 | } 256 | 257 | Result DPLLPro (LiteralsList *LL, ClauseList *CL, TotalNumber TN,Counter *counter) 258 | { 259 | TrueValue stack[TN.totalpNumber]; 260 | Result result; 261 | ClauseNode *Cp; 262 | int top=0,num=1,Cnum,pnum,i,j=1,queue[TN.totalpNumber*2]; 263 | int rear=0,head=0,m=1,backtrack=FALSE,order[TN.totalpNumber*2]; 264 | clock_t start,over; 265 | start=clock(); 266 | stack[top].pTV=(int *)malloc((TN.totalpNumber+1)*sizeof(int)); 267 | for(i=0; i<=TN.totalpNumber; i++) 268 | { 269 | stack[top].pTV[i]=UNDECIDE; 270 | } 271 | ordercounter(order,counter,TN.totalpNumber); 272 | num=order[0]; 273 | while(1) 274 | { 275 | if(m%10==0) 276 | { 277 | for(int k=1; k<=TN.totalpNumber; k++) 278 | { 279 | counter[k].pos/=2; 280 | counter[k].neg/=2; 281 | } 282 | m=1; 283 | } 284 | LiteralsNode *lp2; 285 | backtrack=FALSE; 286 | if(stack[top].pTV[num]==UNDECIDE) 287 | { 288 | top++; 289 | stack[top].pTV=(int *)malloc((TN.totalpNumber+1)*sizeof(int)); 290 | for(i=1; i<=TN.totalpNumber; i++) 291 | stack[top].pTV[i]=stack[top-1].pTV[i]; 292 | stack[top].pTV[num]=DECIDE; 293 | stack[top].num=num; 294 | rear=head=0; 295 | } 296 | if(stack[top].pTV[num]==FALSE) 297 | Cp=LL[num].pos_watched; 298 | else 299 | Cp=LL[num].neg_watched; 300 | while(Cp) 301 | { 302 | Cnum=Cp->clause; 303 | int watch1,watch2,flag2=FALSE; 304 | watch1=CL[Cnum].Watch1->literals; 305 | if(CL[Cnum].Watch2==NULL) 306 | { 307 | if(top==0) 308 | { 309 | return UNSAT(start); 310 | } 311 | else 312 | { 313 | if(CL[Cnum].Watch1->flag==TRUETRUE) 314 | { 315 | counter[watch1].pos++; 316 | } 317 | else 318 | counter[watch1].neg++; 319 | num=stack[top].num; 320 | destroy(&stack[top]); 321 | top--; 322 | stack[top].pTV[num]=FALSE; 323 | backtrack=TRUETRUE; 324 | rear=head=0; 325 | break; 326 | } 327 | } 328 | watch2=CL[Cnum].Watch2->literals; 329 | if(watch1==num||watch2==num) 330 | { 331 | if(watch2==num) 332 | { 333 | int temp; 334 | temp=watch1; 335 | watch1=watch2; 336 | watch2=temp; 337 | flag2=TRUETRUE; 338 | } 339 | int pnum1,flag1=4; 340 | LiteralsNode *lp1; 341 | lp1=CL[Cnum].head; 342 | while(lp1) 343 | { 344 | pnum1=lp1->literals; 345 | if((stack[top].pTV[pnum1]==UNDECIDE)||(stack[top].pTV[pnum1]==lp1->flag)) 346 | { 347 | if(pnum1!=watch2) 348 | { 349 | if(flag2==FALSE) 350 | CL[Cnum].Watch1=lp1; 351 | else 352 | CL[Cnum].Watch2=lp1; 353 | break; 354 | } 355 | else 356 | { 357 | flag1=lp1->flag; 358 | } 359 | } 360 | lp1=lp1->next; 361 | } 362 | if(lp1) 363 | { 364 | Cp=Cp->next; 365 | continue; 366 | } 367 | else 368 | { 369 | if(flag1!=4) 370 | { 371 | if(stack[top].pTV[watch2]!=UNDECIDE) 372 | { 373 | Cp=Cp->next; 374 | continue; 375 | } 376 | else 377 | { 378 | stack[top].pTV[watch2]=flag1; 379 | queue[rear++]=watch2; 380 | } 381 | } 382 | else 383 | { 384 | if(top==0) 385 | { 386 | return UNSAT(start); 387 | } 388 | else 389 | { 390 | lp2=CL[Cnum].head; 391 | while(lp2) 392 | { 393 | if(lp2->flag) 394 | { 395 | counter[lp2->literals].pos++; 396 | } 397 | else 398 | counter[lp2->literals].neg++; 399 | lp2=lp2->next; 400 | } 401 | num=stack[top].num; 402 | destroy(&stack[top]); 403 | top--; 404 | stack[top].pTV[num]=FALSE; 405 | backtrack=TRUETRUE; 406 | rear=head=0; 407 | break; 408 | } 409 | } 410 | } 411 | } 412 | Cp=Cp->next; 413 | } 414 | if(backtrack==TRUETRUE) 415 | continue; 416 | if(head=TN.totalpNumber*2) 434 | { 435 | return SAT(start,stack[top].pTV); 436 | } 437 | } 438 | } 439 | 440 | } 441 | void destroy (TrueValue* TV) 442 | { 443 | free(TV->pTV); 444 | 445 | } 446 | Result UNSAT (clock_t start) 447 | { 448 | Result result; 449 | clock_t over; 450 | over=clock(); 451 | result.SAT=FALSE; 452 | result.time=over-start; 453 | return result; 454 | } 455 | Result SAT(clock_t start,int *pTV) 456 | { 457 | Result result; 458 | clock_t over; 459 | over=clock(); 460 | result.SAT=TRUETRUE; 461 | result.time=over-start; 462 | result.pTV=pTV; 463 | return result; 464 | } 465 | void ordercounter(int *order,Counter *counter,int n) 466 | { 467 | int i,j,t,a[n*2]; 468 | for(i=0; ia[j-1]) 479 | { 480 | t=a[j]; 481 | a[j]=a[j-1]; 482 | a[j-1]=t; 483 | t=order[j],order[j]=order[j-1],order[j-1]=t; 484 | } 485 | else 486 | break; 487 | } 488 | } 489 | } 490 | 491 | status Save (ClauseList *CL,TotalNumber TN) 492 | { 493 | int i; 494 | FILE *fp; 495 | char filename[100]; 496 | printf("请输入要保存的文件:"); 497 | scanf("%s",filename); 498 | fp=fopen(filename,"w"); 499 | if(!fp) 500 | { 501 | printf("文件打开失败!"); 502 | return ERROR; 503 | } 504 | fprintf(fp,"p cnf %d %d\n",TN.totalpNumber,TN.totalCNumber); 505 | LiteralsNode *lp; 506 | for( i=1; i<=TN.totalCNumber; i++) 507 | { 508 | lp=CL[i].head; 509 | while(lp) 510 | { 511 | if(lp->flag) 512 | fprintf(fp,"%d ",lp->literals); 513 | else 514 | fprintf(fp,"%d ",-lp->literals); 515 | lp=lp->next; 516 | } 517 | fprintf(fp,"0\n"); 518 | } 519 | fclose(fp); 520 | } 521 | 522 | 523 | void showCL(ClauseList *CL,int begin,int cn) 524 | { 525 | LiteralsNode *lp; 526 | for(int i=begin; i<=cn; i++) 527 | { 528 | lp=CL[i].head; 529 | printf("C%d:",i); 530 | while(lp) 531 | { 532 | if(lp->flag) 533 | printf("%d ",lp->literals); 534 | else 535 | printf("%d ",-lp->literals); 536 | lp=lp->next; 537 | } 538 | printf("\n"); 539 | } 540 | printf("\n"); 541 | } 542 | void showLL(LiteralsList *LL,int begin,int pn) 543 | { 544 | ClauseNode *cp; 545 | for(int i=begin; i<=pn; i++) 546 | { 547 | printf("L%d:",i); 548 | cp=LL[i].pos_watched; 549 | printf("pos_watched: "); 550 | while(cp) 551 | { 552 | printf("%d ",cp->clause); 553 | cp=cp->next; 554 | } 555 | printf("\n"); 556 | printf("neg_watched: "); 557 | cp=LL[i].neg_watched; 558 | while(cp) 559 | { 560 | printf("%d ",cp->clause); 561 | cp=cp->next; 562 | } 563 | printf("\n"); 564 | } 565 | printf("\n"); 566 | } 567 | 568 | 569 | void deleteclause(int cn,LiteralsList **LL, ClauseList **CL,TotalNumber *TN,Counter **counter) 570 | { 571 | LiteralsNode *lp,*lp1; 572 | ClauseNode *cp,*cp1; 573 | int dpn,dcn,flag,isdelete=FALSE; 574 | lp=(*CL)[cn].head; 575 | while(lp) 576 | { 577 | isdelete=FALSE; 578 | lp1=lp; 579 | lp=lp->next; 580 | dpn=lp1->literals; 581 | flag=lp1->flag; 582 | if(flag==TRUETRUE) 583 | { 584 | (*counter)[dpn].pos--; 585 | cp=(*LL)[dpn].pos_watched; 586 | if(cp->clause==cn) 587 | { 588 | free(cp); 589 | (*LL)[dpn].pos_watched=cp->next; 590 | isdelete=TRUETRUE; 591 | } 592 | } 593 | else 594 | { 595 | (*counter)[dpn].neg--; 596 | cp=(*LL)[dpn].neg_watched; 597 | if(cp->clause==cn) 598 | { 599 | free(cp); 600 | (*LL)[dpn].neg_watched=cp->next; 601 | isdelete=TRUETRUE; 602 | 603 | } 604 | } 605 | if(isdelete==FALSE) 606 | { 607 | cp1=cp; 608 | cp=cp->next; 609 | while(cp) 610 | { 611 | if(cp->clause==cn) 612 | { 613 | cp1->next=cp->next; 614 | free(cp); 615 | break; 616 | } 617 | cp=cp->next; 618 | } 619 | 620 | } 621 | free(lp1); 622 | } 623 | (*CL)[cn].lNumber=0; 624 | (*CL)[cn].Watch2=(*CL)[cn].Watch1=(*CL)[cn].head=NULL; 625 | } 626 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 数据结构实验 2 | 华中科技大学计算机学院数据结构前三次实验全部外加第四次实验报告, 3 | 第四次实验代码忘记保存了。 4 | 最好先看报告,再看代码,不然可能会摸不清在干嘛 5 | # 找学委要到了自己全部的数据结构实验报告,已更新 6 | 7 | -------------------------------------------------------------------------------- /数据结构课程设计报告.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/数据结构课程设计报告.docx -------------------------------------------------------------------------------- /程序设计综合课程设计任务及指导学生包.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/程序设计综合课程设计任务及指导学生包.rar -------------------------------------------------------------------------------- /课程设计最终提交版本/CS1705-U201714726王明明.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/课程设计最终提交版本/CS1705-U201714726王明明.docx -------------------------------------------------------------------------------- /课程设计最终提交版本/CS1705-U201714726王明明.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/课程设计最终提交版本/CS1705-U201714726王明明.exe -------------------------------------------------------------------------------- /课程设计最终提交版本/Game.c: -------------------------------------------------------------------------------- 1 | #ifndef GAME_C_INCLUDED 2 | #define GAME_C_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Sudoku.h" 8 | #include "SAT.h" 9 | /*********************************** 10 | *文件名称:Game.c 11 | *文件描述:数独游戏部分的代码实现 12 | *日 期:2019-2-21 13 | *版 本:V1.0 14 | *@_@||||||||||| 15 | ***********************************/ 16 | 17 | 18 | int Sudoku() { 19 | Clause *S = NULL; 20 | SatAnswer *answer; 21 | FILE *fp; 22 | char filename[100]; 23 | Var_watch var_watch[MaxNumVar + 1]; 24 | int branchDecision[2 * MaxNumVar + 1]; 25 | int sudokuTable[9][9]; 26 | int op = 1; 27 | clock_t start, finish; 28 | double duration; 29 | srand((unsigned) time(NULL)); 30 | while (op) { 31 | printf("\n\n"); 32 | printf("\t\t\t Sudoku\n"); 33 | printf("\t\t************************************\n"); 34 | printf("\t\t\t1. Generate Sudoku 2. Solve Sudoku\n"); 35 | printf("\t\t\t0. Back\n"); 36 | printf("\t\t************************************\n"); 37 | printf("\t\t\tPlease choose your operation[0--2]:"); 38 | scanf("%d", &op); 39 | system("cls"); 40 | switch (op) { 41 | case 1: 42 | start = clock(); 43 | NewSudoku(&S, &answer, var_watch, branchDecision, sudokuTable); 44 | finish = clock(); 45 | duration = (double) (finish - start) / 1000.0; 46 | printf("The time to generate Sudoku is %.3f s\n", duration); 47 | break; 48 | case 2: 49 | InitSat(&S, &answer, var_watch, branchDecision); 50 | /*printf("Input the file path:\n"); 51 | scanf("%s", filename); 52 | fp = fopen(filename, "r");*/ 53 | fp = fopen("D:\\sudoku_rule.txt", "r"); 54 | LoadCnf(&S, answer, var_watch, fp); 55 | fclose(fp); 56 | start = clock(); 57 | SolveSudoku(answer, var_watch, branchDecision, sudokuTable); 58 | finish = clock(); 59 | duration = (double) (finish - start) / 1000.0; 60 | printf("The time to solve Sudoku is %.3f s\n", duration); 61 | break; 62 | case 0: 63 | return 0; 64 | default: 65 | printf("\t\t\tPlease choose your operation again[0~2]:"); 66 | scanf("%d", &op); 67 | } 68 | } 69 | } 70 | 71 | int NewSudoku(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]) { 72 | clock_t a, b; 73 | double d; 74 | a = clock(); 75 | if (GenerateSudoku(S, answer, var_watch, branchDecision) == 0) 76 | return 0; 77 | b = clock(); 78 | d = (double) (b - a) / 1000.0; 79 | printf("The time to generate the final Sudoku is %.3f s\n\n", d); 80 | DigHole(*answer, var_watch, branchDecision, sudokuTable); 81 | } 82 | 83 | int GenerateSudoku(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[]) { 84 | int x, y, z, i, j, k, l; 85 | int dig_order[82], index; 86 | FILE *fp; 87 | fp = fopen("D:\\sudoku_rule.txt", "w"); 88 | fprintf(fp, "p cnf 729 10287\r\n"); 89 | for (x = 0; x < 9; ++x) 90 | for (y = 0; y < 9; ++y) 91 | for (z = 1; z <= 8; ++z) { 92 | for (i = z + 1; i <= 9; ++i) 93 | fprintf(fp, "%d %d 0\r\n", -(81 * x + 9 * y + z), -(81 * x + 9 * y + i));//每个位置,数字1~9至多出现一次 94 | } 95 | for (x = 0; x < 9; ++x) 96 | for (z = 1; z <= 9; ++z) 97 | for (y = 0; y < 8; ++y) { 98 | for (i = y + 1; i < 9; ++i) 99 | fprintf(fp, "%d %d 0\r\n", -(81 * x + 9 * y + z), -(81 * x + 9 * i + z));//每一行,数字1~9至多出现一次 100 | } 101 | for (y = 0; y < 9; ++y) 102 | for (z = 1; z <= 9; ++z) 103 | for (x = 0; x < 8; ++x) { 104 | for (i = x + 1; i < 9; ++i) 105 | fprintf(fp, "%d %d 0\r\n", -(81 * x + 9 * y + z), -(81 * i + 9 * y + z));//每一列,数字1~9至多出现一次 106 | } 107 | for (z = 1; z <= 9; ++z) 108 | for (i = 0; i < 3; ++i) 109 | for (j = 0; j < 3; ++j) { 110 | for (x = 0; x < 3; ++x) 111 | for (y = 0; y < 3; ++y) 112 | fprintf(fp, "%d ", 81 * (3 * i + x) + 9 * (3 * j + y) + z);//数字1~9在每个3×3数独中至少出现一次 113 | fprintf(fp, "0\r\n"); 114 | for (x = 0; x < 3; ++x) { 115 | for (y = 0; y < 3; ++y) { 116 | for (k = x + 1; k < 3; ++k) 117 | for (l = 0; l < 3; ++l) 118 | if (l != y) 119 | fprintf(fp, "%d %d 0\r\n", -(81 * (3 * i + x) + 9 * (3 * j + y) + z), 120 | -(81 * (3 * i + k) + 9 * (3 * j + l) + z));//数字1~9在每个3×3数独中至多出现一次 121 | } 122 | } 123 | } 124 | fclose(fp); 125 | do { 126 | fp = fopen("D:\\sudoku_rule.txt", "r"); 127 | // fp = fopen("C:\\Users\\dell\\Desktop\\base.txt", "r"); 128 | if (fp == NULL) { 129 | printf("Opening \"D:\\sudoku_rule.txt\" failed.\n "); 130 | return 0; 131 | } 132 | InitSat(S, answer, var_watch, branchDecision); 133 | LoadCnf(S, *answer, var_watch, fp); 134 | fclose(fp); 135 | for (j = 1; j <= 81; ++j) 136 | dig_order[j] = j; 137 | for (j = 81; j > 1; --j) { //随机生成初始化顺序 138 | index = rand() % j + 1; 139 | if (j != index) { 140 | dig_order[j] = dig_order[j] ^ dig_order[index]; 141 | dig_order[index] = dig_order[index] ^ dig_order[j]; 142 | dig_order[j] = dig_order[j] ^ dig_order[index]; 143 | } 144 | } 145 | for (k = 0; k < 11;) { //在棋盘中随机选11个格子随机填入1~9 146 | x = (dig_order[j] - 1) / 9; 147 | y = (dig_order[j] - 1) % 9; 148 | z = rand() % 9 + 1; 149 | for (l = 1; l <= 9; ++l) 150 | if (l == z) 151 | (*answer)->value[81 * x + 9 * y + l] = TRUE; 152 | else 153 | (*answer)->value[81 * x + 9 * y + l] = FALSE; 154 | ++k; 155 | } 156 | knownVar = k; 157 | } while (DPLL(*answer, var_watch, branchDecision, 2, -(rand() % 729 + 1)) == UNSATISFIABLE); 158 | return 1; 159 | } 160 | 161 | int DigHole(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]) { 162 | int x, y, z, i, j, k; 163 | int dig_order[82], index, dig = 1; 164 | int firstBranch; 165 | FILE *fp; 166 | clock_t a, b; 167 | a = clock(); 168 | for (i = 1; i <= numVar; ++i) { 169 | answer->branchLevel[i] = 0; 170 | answer->searched[i] = 0; 171 | answer->singleClause[i] = 0; 172 | } 173 | for (x = 0; x < 9; ++x) { //得到终盘结果 174 | for (y = 0; y < 9; ++y) { 175 | for (z = 1; z <= 9; ++z) 176 | if (answer->value[81 * x + 9 * y + z] == TRUE) { 177 | sudokuTable[x][y] = z; 178 | break; 179 | } 180 | } 181 | } 182 | for (j = 1; j <= 81; ++j) 183 | dig_order[j] = j; 184 | for (j = 81; j > 1; --j) { //随机生成挖洞顺序 185 | index = rand() % j + 1; 186 | if (j != index) { 187 | dig_order[j] = dig_order[j] ^ dig_order[index]; 188 | dig_order[index] = dig_order[index] ^ dig_order[j]; 189 | dig_order[j] = dig_order[j] ^ dig_order[index]; 190 | } 191 | } 192 | for (j = 1; j <= 81 - PreassignVar && dig <= 81;) { 193 | b = clock(); 194 | printf("digged = %d digging = %d time = %.3f s\n", j - 1, dig, (double) (b - a) / 1000.0); 195 | dig_watch(sudokuTable); 196 | x = (dig_order[dig] - 1) / 9; 197 | y = (dig_order[dig++] - 1) % 9; 198 | z = sudokuTable[x][y]; 199 | if (z <= 0) //该位置不可挖,寻找下一个位置 200 | continue; 201 | knownVar = 9 * (81 - j); //已经挖掉j个洞 202 | numBranch = 0; 203 | for (i = 1; i <= 9; ++i) //挖去该位置 204 | answer->value[81 * x + 9 * y + i] = UNKNOWN; 205 | if (j < 4) { //挖去个数小于4,解必定唯一 206 | ++j; 207 | sudokuTable[x][y] = 0; 208 | for (k = 1; k <= 9; ++k) //挖去该位置 209 | answer->value[81 * x + 9 * y + k] = UNKNOWN; 210 | continue; 211 | } 212 | for (i = 1; i <= 9; ++i) { //检测挖去该位置解是否唯一 213 | if (i == z) 214 | continue; 215 | firstBranch = 81 * x + 9 * y + i; 216 | answer->searched[81 * x + 9 * y + i] = 1; //锁定i的另一分支 217 | if (DPLL(answer, var_watch, branchDecision, 2, firstBranch) == SATISFIABLE) //挖去该位置有其他解 218 | break; 219 | knownVar = 9 * (81 - j); //已经挖掉j个洞 220 | numBranch = 0; 221 | for (k = 1; k <= numVar; ++k) { //重置终盘 222 | if (!answer->branchLevel[k]) //决策级为0,为初始化条件,不重置 223 | continue; 224 | answer->value[k] = UNKNOWN; 225 | answer->branchLevel[k] = 0; 226 | answer->searched[k] = 0; 227 | answer->singleClause[k] = 0; 228 | } 229 | } 230 | if (i == 10) { //挖去该位置解仍唯一 231 | ++j; 232 | sudokuTable[x][y] = 0; 233 | } else { //挖去该位置解不唯一 234 | if (dig > 81) 235 | break; 236 | sudokuTable[x][y] = -sudokuTable[x][y]; //该位置不可挖去 237 | for (k = 1; k <= numVar; ++k) { //重置终盘 238 | if (!answer->branchLevel[k]) //决策级为0,为初始化条件,不重置 239 | continue; 240 | answer->value[k] = UNKNOWN; 241 | answer->branchLevel[k] = 0; 242 | answer->searched[k] = 0; 243 | answer->singleClause[k] = 0; 244 | } 245 | for (k = 1; k <= 9; ++k) //填入原来的数 246 | if (k == z) 247 | answer->value[81 * x + 9 * y + k] = TRUE; 248 | else 249 | answer->value[81 * x + 9 * y + k] = FALSE; 250 | } 251 | } 252 | fp = fopen("D:\\sudokuTable.txt", "a+"); 253 | printf("The new Sudoku was generated at \"D:\\sudokuTable.txt\"\n"); 254 | printf("%d known positions:\n", 81 - j + 1); 255 | for (x = 0; x < 9; ++x) { //得到生成数独 256 | for (y = 0; y < 9; ++y) { 257 | sudokuTable[x][y] = abs(sudokuTable[x][y]); 258 | if (sudokuTable[x][y] != 0) { 259 | for (i = 1; i <= 9; ++i) { 260 | if (i != sudokuTable[x][y]) 261 | fprintf(fp, "%d 0\r\n", -(81 * x + 9 * y + i)); 262 | else 263 | fprintf(fp, "%d 0\r\n", 81 * x + 9 * y + i); 264 | } 265 | } 266 | if (y != 0 && y % 3 == 0) 267 | printf("| "); 268 | printf("%d ", sudokuTable[x][y]); 269 | } 270 | printf("\n"); 271 | if (x != 8 && x % 3 == 2) 272 | printf("---------------------\n"); 273 | } 274 | fclose(fp); 275 | } 276 | 277 | int SolveSudoku(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]) { 278 | int x, y, z; 279 | FILE *fp; 280 | DPLL(answer, var_watch, branchDecision, 1, 1); 281 | for (x = 0; x < 9; ++x) { //得到终盘结果 282 | for (y = 0; y < 9; ++y) { 283 | for (z = 1; z <= 9; ++z) 284 | if (answer->value[81 * x + 9 * y + z] == TRUE) { 285 | sudokuTable[x][y] = z; 286 | break; 287 | } 288 | } 289 | } 290 | fp = fopen("D:\\sudokuAnswer.txt", "w"); 291 | printf("The answer to Sudoku was saved at \"D:\\sudokuAnswer.txt\"\n"); 292 | for (x = 0; x < 9; ++x) { //保存并打印数独答案 293 | for (y = 0; y < 9; ++y) { 294 | sudokuTable[x][y] = abs(sudokuTable[x][y]); 295 | if (sudokuTable[x][y] != 0) { 296 | for (int i = 1; i <= 9; ++i) { 297 | if (i != sudokuTable[x][y]) 298 | fprintf(fp, "%d 0\r\n", -(81 * x + 9 * y + i)); 299 | else 300 | fprintf(fp, "%d 0\r\n", 81 * x + 9 * y + i); 301 | } 302 | } 303 | if (y != 0 && y % 3 == 0) 304 | printf("| "); 305 | printf("%d ", sudokuTable[x][y]); 306 | } 307 | printf("\n"); 308 | if (x != 8 && x % 3 == 2) 309 | printf("---------------------\n"); 310 | } 311 | fclose(fp); 312 | } 313 | int dig_watch(int sudokuTable[9][9]) { 314 | int x, y; 315 | for (x = 0; x < 9; ++x) { //保存并打印数独答案 316 | for (y = 0; y < 9; ++y) { 317 | printf("%2d ", sudokuTable[x][y]); 318 | } 319 | printf("\n"); 320 | } 321 | printf("\n\n"); 322 | } 323 | 324 | int dig_test(Clause **S, SatAnswer **answer, Var_watch *var_watch, int *branchDecision) { 325 | FILE *fp; 326 | Clause *S1 = NULL; 327 | Var_watch var_watch1[MaxNumVar + 1]; 328 | int branchDecision1[2 * MaxNumVar + 1]; 329 | int sudokuTable[9][9]; 330 | InitSat(S, answer, var_watch, branchDecision); 331 | fp = fopen("C:\\Users\\dell\\Desktop\\sudoku_rule.txt", "r"); //初始棋盘 332 | LoadCnf(S, *answer, var_watch, fp); 333 | fclose(fp); 334 | InitSat(&S1, answer, var_watch1, branchDecision1); 335 | fp = fopen("D:\\sudoku_answer.txt", "r"); //测试终盘 336 | LoadCnf(&S1, *answer, var_watch1, fp); 337 | fclose(fp); 338 | DigHole(*answer, var_watch, branchDecision, sudokuTable); 339 | } 340 | 341 | 342 | #endif // GAME_C_INCLUDED 343 | -------------------------------------------------------------------------------- /课程设计最终提交版本/SAT.h: -------------------------------------------------------------------------------- 1 | #ifndef SAT_H_INCLUDED 2 | #define SAT_H_INCLUDED 3 | 4 | #define MaxNumVar 4000 5 | #define PreassignVar 18 6 | //预先分配的变元数目 7 | #define CONFLICT 0 8 | #define SATISFIABLE 1 9 | #define UNSATISFIABLE 0 10 | #define OTHERS 2 11 | 12 | #define SINGLE -1 13 | 14 | //UNKNOWN表示该变元未知,NONE表示该变元不存在,FALSE表示该变元为假,TRUE表示该变元为真 15 | #define FALSE -1 16 | #define TRUE 1 17 | #define UNKNOWN 0 18 | #define NONE 2 19 | /*********************************** 20 | *文件名称:SAT.h 21 | *文件描述:关于求解SAT问题的函数声明、数据结构定义 22 | *日 期:2019-2-21 23 | *版 本:V1.0 24 | *@_@||||||||||| 25 | ***********************************/ 26 | 27 | //该结构参考双文字监视方法,可看作两张表格 28 | typedef struct varWatch { 29 | struct varList *pos; //文字邻接表,正文字邻接表,负文字邻接表, 30 | struct varList *neg; 31 | } Var_watch; 32 | 33 | typedef struct varList { 34 | struct clause *p; //指向一个子句 35 | struct varList *next; //指向下一个包含该文字的子句 36 | } VarList; 37 | 38 | typedef struct clause { 39 | struct clauseLiteral *p;//指向一个子句中的下一个文字 40 | struct clause *nextClause;//这个在邻接表中无意义,要从读取CNF文件时看出效果 41 | } Clause; 42 | 43 | typedef struct clauseLiteral { 44 | int data;//文字的值 45 | struct clauseLiteral *next; //指向子句中的下一个文字 46 | } ClauseLiteral; 47 | 48 | typedef struct satAnswer { 49 | int branchLevel[MaxNumVar + 1]; //赋值时的决策树高度 50 | int value[MaxNumVar + 1]; //TRUE or FALSE or UNKNOWN or NONE 51 | int searched[MaxNumVar + 1]; //已被搜索的情况数 52 | int singleClause[MaxNumVar + 1]; //标记是否存在该变量的单子句 53 | } SatAnswer; 54 | 55 | int InitSat(Clause **S, SatAnswer **answer, Var_watch *var_watch, int *branchDecision); 56 | 57 | int Sat(); 58 | 59 | int LoadCnf(Clause **S, SatAnswer *answer, Var_watch var_watch[], FILE *fp); 60 | 61 | int GetNum(FILE *fp); 62 | 63 | int DPLL(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int op, int firstBranch); 64 | 65 | int PrintAnswer(SatAnswer *answer, int result, char filename[100], int duration); 66 | 67 | int PutClause(Clause *ctemp, int var, Var_watch var_watch[]); 68 | 69 | int Deduce(int blevel, SatAnswer *answer, Var_watch var_watch[], int branchDecision[], VarList *root); 70 | 71 | int SingleClauseDeduce(int blevel, SatAnswer *answer, Var_watch var_watch[], int branchDecision[], VarList **vp); 72 | 73 | int NextBranch(int branchDecision[], SatAnswer *answer); 74 | 75 | int Analyse_conflict(int *blevel, int var, SatAnswer *answer); 76 | 77 | int ChectAnswer(Clause *S, SatAnswer *answer); 78 | 79 | int numVar; 80 | int knownVar; 81 | int numBranch; 82 | int firstBranch[MaxNumVar]; 83 | 84 | #endif // SAT_H_INCLUDED 85 | -------------------------------------------------------------------------------- /课程设计最终提交版本/Sudoku.h: -------------------------------------------------------------------------------- 1 | #ifndef SUDOKU_H_INCLUDED 2 | #define SUDOKU_H_INCLUDED 3 | #include "SAT.h" 4 | /*********************************** 5 | *文件名称:Sudoku.h 6 | *文件描述:用来定义数独游戏相关的函数 7 | *日 期:2019-2-21 8 | *版 本:V1.0 9 | *@_@||||||||||| 10 | ***********************************/ 11 | 12 | 13 | int Sudoku(); 14 | 15 | int NewSudoku(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]); 16 | 17 | int GenerateSudoku(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[]); 18 | 19 | int DigHole(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]); 20 | 21 | int SolveSudoku(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int sudokuTable[9][9]); 22 | int dig_watch(int sudokuTable[9][9]); 23 | int dig_test(Clause **S, SatAnswer **answer, Var_watch *var_watch, int *branchDecision); 24 | 25 | 26 | #endif // SUDOKU_H_INCLUDED 27 | -------------------------------------------------------------------------------- /课程设计最终提交版本/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "SAT.h" 6 | #include "Sudoku.h" 7 | /*********************************** 8 | *文件名称:main.c 9 | *文件描述:主界面的显示、函数调用 10 | *日 期:2019-2-21 11 | *版 本:V1.0 12 | *@_@||||||||||| 13 | ***********************************/ 14 | 15 | 16 | int main() { 17 | int op = 1; 18 | while (op) { 19 | printf("\n\n"); 20 | printf("\t\t\t Main Menu \n"); 21 | printf("\t\t************************************\n"); 22 | printf("\t\t\t1. Sudoku 2. SAT\n"); 23 | printf("\t\t\t0. Exit\n"); 24 | printf("\t\t************************************\n"); 25 | printf("\t\t\tPlease choose your operation[0--2]:"); 26 | scanf("%d", &op); 27 | system("cls"); 28 | switch (op) { 29 | case 1: 30 | Sudoku(); 31 | break; 32 | case 2: 33 | Sat(); 34 | break; 35 | case 0: 36 | exit(0); 37 | default: 38 | printf("\t\t\tPlease choose your operation again[0--2]:"); 39 | scanf("%d", &op); 40 | } 41 | } 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /课程设计最终提交版本/satSolve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "SAT.h" 5 | /*********************************** 6 | *文件名称:satSolve.c 7 | *文件描述:解决SAT问题的函数实现 8 | *日 期:2019-2-21 9 | *版 本:V1.0 10 | *@_@||||||||||| 11 | ***********************************/ 12 | 13 | int InitSat(Clause **S, SatAnswer **answer, Var_watch var_watch[], int branchDecision[]) { 14 | Clause *cfront = *S, *crear; //子句的前后指针,用于清空 15 | ClauseLiteral *lfront, *lrear; //文字的前后指针 16 | //子句初始化 17 | while (cfront) { 18 | crear = cfront->nextClause; //这两行可以理解为一个表格从左上角出发 19 | lfront = cfront->p; 20 | while (lfront) { 21 | lrear = lfront->next; 22 | free(lfront); 23 | lfront = lrear; //逐一清空子句中的文字,清空表格中的一行 24 | } 25 | free(cfront); 26 | cfront = crear; //清除完毕之后,由于free了前指针。。。 27 | } 28 | *S = NULL; 29 | //解初始化 30 | numVar = 0; //变元数目为0 31 | knownVar = 0; //已知变元数目为0 32 | numBranch = 0; //分支数目为0 33 | *answer = (SatAnswer *) malloc(sizeof(SatAnswer)); //给answer结构分配空间 34 | for (int i = 1; i <= MaxNumVar; ++i) { 35 | //解初始化 36 | (*answer)->value[i] = NONE; //表示变元不存在 37 | (*answer)->branchLevel[i] = 0; //赋值时决策树高度为0 38 | (*answer)->searched[i] = 0; //已被搜索的情况数是0 39 | (*answer)->singleClause[i] = 0; //该变量的单子句数目为0 40 | //文字邻接表初始化 41 | var_watch[i].pos = (VarList *) malloc(sizeof(VarList)); //为正文字邻接表指针分配空间 42 | var_watch[i].pos->next = NULL; //正文字邻接表指针指向空 43 | var_watch[i].neg = (VarList *) malloc(sizeof(VarList)); //为负文字邻接表指针分配空间 44 | var_watch[i].neg->next = NULL; //负文字邻接表指针指向空 45 | } 46 | //分支决策计数器初始化 47 | for (int j = 1; j <= 2 * MaxNumVar; ++j) 48 | branchDecision[j] = 0; //分支决策计数器初始化为0 49 | } 50 | 51 | int Sat() { 52 | Clause *S = NULL; //子句指针 53 | SatAnswer *answer; //SAT解的指针 54 | Var_watch var_watch[MaxNumVar + 1]; //最大变元数目加一个空间 55 | FILE *fp; //文件指针 56 | char filename[100]; //文件名 57 | int branchDecision[2 * MaxNumVar + 1]; //决策树最大分支 应该是变元数目的二倍加一(一个变元有两种可能) 58 | int op = 1,result; 59 | clock_t start, finish; //调用的time.h头文件 60 | int duration; //用于表示耗时 61 | while (op) { 62 | printf("\n\n"); 63 | printf("\t\t\t\t SAT\n"); 64 | printf("\t\t\t******************************************\n"); 65 | printf("\t\t\t1. New SAT 2. Check Answer\n"); 66 | printf("\t\t\t0. Back\n"); 67 | printf("\t\t\t******************************************\n"); 68 | printf("\t\t\tPlease choose your operation[0--2]:"); 69 | scanf("%d", &op); 70 | system("cls"); 71 | switch (op) { 72 | case 1://case1意味着要读取cnf文件,首先要初始化,因此有下一行 73 | InitSat(&S, &answer, var_watch, branchDecision); 74 | printf("Please input the file path:\n"); 75 | scanf("%s", filename); 76 | fp = fopen(filename, "r"); 77 | 78 | if (fp == NULL) { 79 | printf("fail to open the file!\n "); 80 | break; 81 | } else LoadCnf(&S, answer, var_watch, fp); //调用LoadCnf 函数,读取文件 82 | start = clock(); //调用time.h,记录开始时间 83 | result = DPLL(answer, var_watch, branchDecision, 1, 1); 84 | finish = clock(); //调用time.h,记录结束时间 85 | duration = (finish - start);//得到解决问题的耗时 86 | if (result == SATISFIABLE) 87 | { 88 | printf("Time to solve the SAT problem %d ms\n", duration); 89 | PrintAnswer(answer, 1, filename, duration); 90 | } 91 | else 92 | { 93 | printf("No solution!\n"); 94 | PrintAnswer(answer, 0, filename, duration); 95 | } 96 | break; 97 | case 2: 98 | ChectAnswer(S, answer); 99 | break; 100 | case 0: 101 | return 0; 102 | default: 103 | printf("\t\t\tPlease choose your operation again[0~2]:"); 104 | scanf("%d", &op); 105 | } 106 | } 107 | } 108 | 109 | int LoadCnf(Clause **S, SatAnswer *answer, Var_watch var_watch[], FILE *fp) {//加载CNF文件 110 | char c; 111 | Clause *ctemp, *cp = NULL; //两个指针,加载CNF文件中的子句会用到 112 | ClauseLiteral *lp, *ltemp; //两个指针,加载CNF文件中的文字会用到 113 | int var; //变量的值 114 | int numClauseVar; //每个子句的变元数 115 | fscanf(fp, "%c", &c); 116 | while (c == 'c') { //注释段 117 | while (c != '\n' && c != '\r') // 118 | fscanf(fp, "%c", &c); // 119 | fscanf(fp, "%c", &c); 120 | if (c == '\n') //如果读取到换行符,意味着要再重复一次 121 | fscanf(fp, "%c", &c); 122 | } 123 | fscanf(fp, " cnf "); //开始读到文件的信息段 124 | numVar = GetNum(fp); //读取变量数,并赋值给numVar 125 | GetNum(fp); //读取子句数 126 | var = GetNum(fp); //再次调用,读取下一行第一个变量值,把值赋给var 127 | while (1) { 128 | numClauseVar = 0; 129 | ctemp = (Clause *) malloc(sizeof(Clause)); //为ctemp指针分配空间 130 | lp = ctemp->p; //lp为文字指针,,可以想象一下表格长什么样 131 | while (var) { 132 | ++numClauseVar; //计数器功能,统计每个子句的变元数目 133 | if (answer->value[abs(var)] == NONE) 134 | answer->value[abs(var)] = UNKNOWN; 135 | ltemp = (ClauseLiteral *) malloc(sizeof(ClauseLiteral)); 136 | ltemp->data = var; //文字的值域改成var,赋值 137 | ltemp->next = NULL; // 138 | if (numClauseVar == 1) { //储存子句中首个变量 139 | ctemp->p = lp = ltemp; 140 | } else { //储存子句中非首个变量 141 | lp->next = ltemp; 142 | lp = lp->next; 143 | } 144 | if (var > 0) 145 | ++firstBranch[var]; //初始分支决策计数增加 146 | else 147 | ++firstBranch[numVar - var]; 148 | PutClause(ctemp, var, var_watch); //储存各变量的子句地址 149 | var = GetNum(fp); 150 | } 151 | if (numClauseVar == 1) { //输入单子句,则该子句必须满足,无需存入 152 | answer->value[abs(lp->data)] = lp->data / abs(lp->data); 153 | ++knownVar; //已知变元数目加1 154 | } else if (*S == NULL) { 155 | *S = cp = ctemp; 156 | cp->nextClause = NULL; 157 | } else { //想想表格的形式,是列的头 158 | cp->nextClause = ctemp; 159 | cp = cp->nextClause; 160 | cp->nextClause = NULL; 161 | } 162 | var = GetNum(fp); //若到达文件尾,再执行一次z'z 读文件操作时,设置文件结束标志 163 | if (feof(fp)) 164 | break; 165 | } 166 | } 167 | 168 | int GetNum(FILE *fp) {//这个函数用来读取cnf文件时得到变量数、子句数、后面的内容 169 | char c; 170 | int sign = 1, num = 0; //num 用来得到文字的值,sign用来标记文字是正或者负 171 | fscanf(fp, "%c", &c); 172 | if (c == '-') { 173 | sign = -1; //sign变为-1,表示为负文字 174 | fscanf(fp, "%c", &c); 175 | } else if (c == '0') { //表示该条子句结束 176 | fscanf(fp, "%c", &c); 177 | if (c == '\r') //表示换行 178 | fscanf(fp, "%c", &c); 179 | return num; // 180 | } else if (feof(fp)) //如果是结束标记 181 | return 0; 182 | while (c != ' ' && c != '\n' && c != '\r') { 183 | num = num * 10 + c - '0'; //得到文字的值 184 | fscanf(fp, "%c", &c); 185 | } 186 | if (c == '\r') 187 | fscanf(fp, "%c", &c); 188 | return sign * num; //用来得到文字(包括正负和值) 189 | } 190 | 191 | int DPLL(SatAnswer *answer, Var_watch var_watch[], int branchDecision[], int op, int firstBranch) { 192 | int status, var, blevel = 0; //初始判定级为0 193 | VarList *vp; //邻接表指针,用于 194 | while (1) { 195 | if (numBranch++ == 0) { //第一次分支决策 196 | if (op == 1) //1:SAT求解、2:生成数独的检验求解 197 | var = NextBranch(branchDecision, answer); 198 | else 199 | var = firstBranch; 200 | } else 201 | var = NextBranch(branchDecision, answer); //下一分支决策 202 | ++blevel; //判定级加1 203 | answer->value[abs(var)] = var / abs(var); //进入一分支 204 | answer->branchLevel[abs(var)] = blevel; 205 | ++answer->searched[abs(var)]; //已被搜索情况数加1 206 | ++knownVar; //已知变元数目加1 207 | while (1) { 208 | if (var > 0) 209 | vp = var_watch[var].neg->next; //var为TRUE,则搜索var为FALSE的子句 210 | else 211 | vp = var_watch[-var].pos->next; //var为FALSE,则搜索var为TRUE的子句 212 | status = Deduce(blevel, answer, var_watch, branchDecision, vp);//单子句传播,返回子句的状态 213 | if (status == SATISFIABLE) //满足的情况 214 | return SATISFIABLE; 215 | else if (status == CONFLICT) { 216 | var = Analyse_conflict(&blevel, var, answer);//var > 0,矛盾,开始回溯 217 | if (blevel == 0) 218 | return UNSATISFIABLE; 219 | else { //进入另一分支,不满足 220 | answer->value[var] = -answer->value[var];//则值进行反转,正变成负,负变成正 221 | ++answer->searched[var]; //被搜索情况数目加1 222 | if (answer->value[var] < 0) 223 | var = -var; 224 | } 225 | } else if (status == OTHERS) break; //已知条件不足,进入下一层 226 | } 227 | } 228 | } 229 | 230 | int PrintAnswer(SatAnswer *answer,int result, char filename[100], int duration) { 231 | FILE *fp; 232 | fp = filename; 233 | int p = 0; 234 | while (filename[p] != 0) p++; 235 | while (filename[p] != '.') p--; 236 | p++; 237 | filename[p] = 'r'; 238 | p++; 239 | filename[p] = 'e'; 240 | p++; 241 | filename[p] = 's'; 242 | p++; 243 | filename[p] = 0; 244 | fp = fopen(fp, "w"); 245 | if(result == 1) 246 | fprintf(fp, "s 1\r\n"); 247 | else 248 | fprintf(fp, "s 0\r\n"); 249 | fprintf(fp, "v "); 250 | for(int i = 1; i < MaxNumVar; i++) 251 | { 252 | if(answer->value == TRUE) 253 | fprintf(fp, "%d ", i); 254 | else 255 | fprintf(fp, "-%d ", i); 256 | } 257 | fprintf(fp, "\r\n"); 258 | fprintf(fp, "t %d\r\n", duration); 259 | fclose(fp); 260 | printf("The answer has been saved\n"); 261 | printf("One solution of SAT is:\n"); 262 | for (int i = 1; i <= MaxNumVar; ++i) 263 | if (answer->value[i] == TRUE) 264 | { 265 | printf("%d ", i); 266 | //fprintf(file, "%d ", i); 267 | } 268 | else if (answer->value[i] == FALSE) 269 | printf("-%d ", i); 270 | printf("\n"); 271 | 272 | //fflush(file); 273 | 274 | } 275 | 276 | int PutClause(Clause *ctemp, int var, Var_watch var_watch[]) { 277 | VarList *wp; 278 | if (var > 0) //判断var是否大于零,从而归纳到相应的表格中 279 | wp = var_watch[var].pos; 280 | else 281 | wp = var_watch[-var].neg; 282 | while (wp->next) 283 | wp = wp->next; //循环,找到VarList的尾部,将var添加到尾部 284 | wp->next = (VarList *) malloc(sizeof(VarList));//分配空间 285 | wp = wp->next; // 286 | wp->p = ctemp; //将子句放在末尾 287 | wp->next = NULL; 288 | } 289 | 290 | int Deduce(int blevel, SatAnswer *answer, Var_watch var_watch[], int branchDecision[], VarList *root) { 291 | int top = 0, status; //status表示状态 292 | VarList *stack[MaxNumVar], *vp = root; //栈,栈的最大长度为最大变元数目 293 | stack[top++] = vp; 294 | while (top) { 295 | vp = stack[top - 1]; //访问栈顶元素 296 | status = SINGLE; 297 | while (status == SINGLE && vp) { //左子树搜索 298 | status = SingleClauseDeduce(blevel, answer, var_watch, branchDecision, &vp); 299 | stack[top++] = vp; //左孩子入栈 300 | } 301 | --top; //空指针退栈 302 | if (status == CONFLICT) 303 | return CONFLICT; 304 | if (top) { //右子树搜索 305 | vp = stack[--top]; //根节点出栈 306 | if (vp->next) 307 | stack[top++] = vp->next; //右孩子入栈 308 | } 309 | } 310 | if (knownVar < numVar) 311 | return OTHERS; 312 | else return SATISFIABLE; 313 | } 314 | 315 | int SingleClauseDeduce(int blevel, SatAnswer *answer, Var_watch var_watch[], int branchDecision[], VarList **vp) { 316 | Clause *cp; //子句指针 317 | ClauseLiteral *lp; //文字指针 318 | int unknownNum, firstUnknown, satisfiable; // 319 | //初始化 320 | unknownNum = 0; 321 | firstUnknown = 0; 322 | satisfiable = 0; 323 | cp = (*vp)->p; //将cp指向vp所指向的子句 324 | lp = cp->p; //文字指针指向cp所指向的文字 325 | if (lp == NULL) 326 | return OTHERS; 327 | while (lp) { 328 | if (lp->data > 0) 329 | ++branchDecision[lp->data]; //分支决策计数增加 330 | else 331 | ++branchDecision[numVar - lp->data]; 332 | if (answer->value[abs(lp->data)] * lp->data > 0) { //子句中存在值为TRUE的文字,子句成立 333 | satisfiable = 1; 334 | break; 335 | } 336 | if (answer->value[abs(lp->data)] == UNKNOWN) { 337 | ++unknownNum; //计数子句中未被赋值的文字, 338 | if (firstUnknown == 0) 339 | firstUnknown = lp->data; //记录第一个未知的文字 340 | } 341 | lp = lp->next; 342 | } 343 | if (unknownNum == 0 && satisfiable == 0) //该子句文字均已知并且都为FALSE,为矛盾句 344 | return CONFLICT; 345 | else if (unknownNum == 1 && satisfiable == 0) { //该子句无值为TRUE的文字,且只有一个未知文字,为单子句 346 | answer->singleClause[abs(firstUnknown)] = 1; //标记,单子句出现的位置 347 | answer->value[abs(firstUnknown)] = firstUnknown / abs(firstUnknown); 348 | answer->branchLevel[abs(firstUnknown)] = blevel; 349 | ++knownVar; //已被赋值的变元数目加1,即确定变元数目加1 350 | if (firstUnknown > 0) 351 | *vp = var_watch[firstUnknown].neg->next; //var为TRUE,则检索var为FALSE的子句 352 | else 353 | *vp = var_watch[-firstUnknown].pos->next; //var为FALSE,则检索var为TRUE的子句 354 | return SINGLE; 355 | } else if (knownVar < numVar) { 356 | *vp = NULL; 357 | return OTHERS; //判断条件不足,返回OTHERS 358 | } else return SATISFIABLE; 359 | } 360 | 361 | int NextBranch(int branchDecision[], SatAnswer *answer) {//下一分支函数 362 | int maxVar = numVar, maxCount = 0; 363 | int *branch; 364 | ++numBranch; 365 | branch = numBranch == 1 ? firstBranch : branchDecision; 366 | for (int i = 1; i <= 2 * numVar; ++i) { 367 | if (i <= numVar && answer->value[i] != UNKNOWN) 368 | continue; 369 | if (i > numVar && answer->value[i - numVar] != UNKNOWN) 370 | continue; 371 | if (maxCount <= *(branch + i)) { 372 | maxVar = i; 373 | maxCount = *(branch + i); 374 | 375 | } 376 | //maxVar = i; 377 | } 378 | return maxVar > numVar ? numVar - maxVar : maxVar; 379 | } 380 | 381 | int Analyse_conflict(int *blevel, int var, SatAnswer *answer) {//回溯函数 382 | int fore = abs(var); 383 | while (*blevel != 0) { 384 | for (int j = 1; j <= numVar; ++j) 385 | if (j != fore && answer->branchLevel[j] == *blevel) { //将由var赋值产生的单子句重置 386 | answer->value[j] = UNKNOWN; 387 | answer->branchLevel[j] = 0; 388 | answer->searched[j] = 0; 389 | answer->singleClause[j] = 0; 390 | --knownVar; 391 | } 392 | if (*blevel != 1) { 393 | if (answer->searched[fore] == 2) { //var的TRUE和FALSE分支均搜索过,进行回溯 394 | --(*blevel); 395 | answer->value[fore] = UNKNOWN; 396 | answer->branchLevel[fore] = 0; 397 | answer->searched[fore] = 0; 398 | --knownVar; 399 | for (int i = 1; i <= numVar; ++i) 400 | if (answer->branchLevel[i] == *blevel && answer->singleClause[i] == 0) { 401 | fore = i; 402 | break; 403 | } 404 | } else break; //搜索另一分支 405 | } else if (answer->searched[abs(fore)] == 2)//blevel1全部搜索完 406 | --(*blevel); 407 | else break; //搜索blevel1的另一分支 408 | } 409 | return fore; 410 | } 411 | 412 | int ChectAnswer(Clause *S, SatAnswer *answer) {//解的正误检查 413 | FILE *fp; 414 | Clause *cp = S; 415 | VarList *error = NULL, *ep; 416 | ClauseLiteral *lp; 417 | int ok = 0, s = 1, num = 0; 418 | fp = fopen("D:\\Satcheck.txt", "w");//在D盘建立一个txt文件 419 | error = ep = (VarList *) malloc(sizeof(VarList));//分配空间 420 | error->next = NULL; 421 | fprintf(fp, "Answer:\r\n"); 422 | for (int i = 1; i <= MaxNumVar; ++i) 423 | if (answer->value[i] == TRUE)//标记的第i个值为正文字 424 | fprintf(fp, "%d ", i); 425 | else if (answer->value[i] == FALSE)//标记的第i个值为负文字 426 | fprintf(fp, "-%d ", i); 427 | fprintf(fp, "\r\n\r\n"); 428 | while (cp) { 429 | ok = 0; 430 | lp = cp->p; 431 | fprintf(fp, "C%-4d ", ++num); 432 | while (lp) { 433 | fprintf(fp, "%4d ", lp->data); 434 | if (answer->value[abs(lp->data)] * lp->data > 0) 435 | ok = 1; 436 | lp = lp->next; 437 | } 438 | if (ok == 1) 439 | fprintf(fp, "T\r\n"); 440 | else { 441 | s = 0; 442 | fprintf(fp, "F\r\n"); 443 | ep->next = (VarList *) malloc(sizeof(VarList)); 444 | ep = ep->next; 445 | ep->p = cp; 446 | ep->next = NULL; 447 | } 448 | cp = cp->nextClause; 449 | } 450 | if (s == 1) 451 | printf("Check: Satisfiable!\n"); 452 | else printf("Check: Unsatisfiable!\n");//检查的结果 453 | printf("The detail was saved at \"D:\\Satcheck.txt\"\n");//保存在哪里了 454 | ep = error->next; 455 | if (ep) { 456 | fprintf(fp, "\r\n\r\nError:\r\n"); 457 | num = 0; 458 | } 459 | while (ep) { 460 | fprintf(fp, "C%-4d ", ++num); 461 | lp = ep->p->p; 462 | while (lp) { 463 | fprintf(fp, "%4d ", lp->data); 464 | lp = lp->next; 465 | } 466 | fprintf(fp, "F\r\n"); 467 | ep = ep->next; 468 | } 469 | fclose(fp); 470 | } 471 | -------------------------------------------------------------------------------- /课程设计最终提交版本/操作手册.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/课程设计最终提交版本/操作手册.docx -------------------------------------------------------------------------------- /资料.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chu-Wang/DataStructLab/0c05c2d83d86a9eff6cff2646e62df00092cb606/资料.zip --------------------------------------------------------------------------------