//皇后问题最快的解法(C语言)八皇后、十六皇后时间在毫秒级
#include <windows.h> # include<stdio.h> # include<stdlib.h> # include<time.h> #define O 134775813 // TODO (xubo18056052430#1#): PB10210016 徐波 LARGE_INTEGER lv,lv1,lv2,lv3,lv4; double totaltime,secondsPerTick; int step; /***********************************************************************************************/ int dn(int n) //分组,根据经验值产生,网搜得到--取下列值是比较好,返回不同的值对实验结果影响很大 { if (n < 100) return n; else if (n < 1000) return 40; else if (n < 10000) return 60; else if (n < 100000) return 90; else return 150; } /***********************************************************************************************/ /***********************************************************************************************/ int rand1 = (unsigned)time(NULL); //rand1产生随机数 int rand2(int range) //rand1线性同余随机数产生器 { unsigned int x = 0x7fffffff, m, c = 1, a =O; m = x + 1; rand1 = (rand1 * a + 1)%m; double r =(double) rand1 / x; int r2 = (int)(r * range); return r2; } /***********************************************************************************************/ /***********************************************************************************************/ void swap(int &a, int &b){ //交换两值 int c; c = a;a = b;b = c; } /***********************************************************************************************/ /***********************************************************************************************/ int chongtu(int n, int line1[], int line2[]){ //冲突 int xubo = 0; for(int i = 0; i < n + n; i ++){ if(line1[i] > 1){xubo = xubo + (line1[i] * (line1[i] - 1)) / 2;} if(line2[i] > 1){xubo = xubo + (line2[i] * (line2[i] - 1)) / 2;} } return xubo; } /***********************************************************************************************/ /***********************************************************************************************/ int improve(int i, int j, int n, int q[], int line1[], int line2[]) //判断q[i]和q[j])交换后冲突的个数是否会减少 { int xubo = 0; xubo = xubo + (1 - line1[i + q[i]]); xubo = xubo + (1 - line2[i - q[i] + n - 1]); xubo = xubo + (1 - line1[j + q[j]]); xubo = xubo + (1 - line2[j - q[j] + n - 1]); xubo = xubo + line1[i + q[j]]; xubo = xubo + line2[i - q[j] + n - 1]; xubo = xubo + line1[j + q[i]]; xubo = xubo + line2[j - q[i] + n - 1]; if(i + q[i] == j + q[j] || i - q[i] == j - q[j]) xubo = xubo + 2; return xubo; } /***********************************************************************************************/ /***********************************************************************************************/ void csh(int n, int m, int q[], int line1[], int line2[]) { int i, end, rand3; bool *l1 = (bool *)malloc((n + n) * sizeof(bool)); bool *l2 = (bool *)malloc((n + n) * sizeof(bool)); for(i = 0; i < n; i ++) { q[i] = i; line1[i] = 0; line2[i] = 0; l1[i] = false; l2[i] = false; } for(i = n; i < n + n; i ++) { line1[i] = 0; line2[i] = 0; l1[i] = false; l2[i] = false; } for(i = 0, end = n; i < m; i ++, end --) //初始化(0 ~ m - 1);前m行不会此时不会产生冲突 { //初始化后横竖无冲突,只要保证两斜线无冲突即可 do { rand3 = i + rand2(end); }while(l1[i + q[rand3]] || l2[i - q[rand3] + n - 1]); swap(q[i], q[rand3]); line1[i + q[i]] ++; line2[i - q[i] + n - 1] ++; l1[i + q[i]] = true; l2[i - q[i] + n - 1] = true; } for(i = m, end = n - m; i < n; i ++, end--) //初始化line { rand3 = i + rand2(end); swap(q[i], q[rand3]); line1[i + q[i]] ++; line2[i - q[i] + n - 1] ++; } free(l1); free(l2); } /***********************************************************************************************/ /***********************************************************************************************/ void work(int n, int m, int q[]) { QueryPerformanceFrequency( &lv ); secondsPerTick = 1000000.0 / lv.QuadPart; int temp, reduce, i, j; step = 0; int *line1 = (int *)malloc((n + n) * sizeof(int)); int *line2 = (int *)malloc((n + n) * sizeof(int)); QueryPerformanceCounter( &lv3 ); csh(n, m, q, line1, line2); QueryPerformanceCounter( &lv4 ); totaltime = secondsPerTick * (lv4.QuadPart-lv3.QuadPart); printf("\n初始化时间为:%e s ", totaltime/1000000); //初始化时间 temp = chongtu(n, line1, line2); //printf("冲突次数= %d\n", temp); while(temp > 0){ reduce = 0; for(i = m; i < n; i ++){ if(line1[i + q[i]] == 1 && line2[i - q[i] + n - 1] == 1) continue; else{ for(j = 0; j < n; j ++){ if(i != j){ reduce = improve(i, j, n, q, line1, line2); if(reduce < 0) break; } } if(reduce < 0) //可交换q[i]和q[j],使总的冲突减少 break; } } if(reduce < 0){ step ++; line1[i + q[i]] --; line2[i - q[i] + n - 1] --; line1[j + q[j]] --; line2[j - q[j] + n - 1] --; swap(q[i], q[j]); line1[i + q[i]] ++; line2[i - q[i] + n - 1] ++; line1[j + q[j]] ++; line2[j - q[j] + n - 1] ++; temp = temp + reduce; } else { csh(n, m, q, line1, line2); temp = chongtu(n, line1, line2); } } } /***********************************************************************************************/ /***********************************************************************************************/ size_t **NQueen(size_t q_xubober) //实验要求size_t **NQueen(size_t Queen_xubober) { LARGE_INTEGER lv,lv1,lv2; double totaltime,secondsPerTick; QueryPerformanceFrequency( &lv ); secondsPerTick = 1000000.0 / lv.QuadPart; unsigned int **ee = (unsigned int **)malloc(4 * sizeof(unsigned int *)), loop = 3, i, j; for(i = 1; i < 4; i ++) ee[i] = (unsigned int *)malloc((q_xubober + 1) * sizeof(unsigned int)); int *q = (int *)malloc(q_xubober * sizeof(int)); int m = q_xubober - dn(q_xubober); printf("\n问题大小N= %d m= %d\n*************************************************************************\n", q_xubober, m); for(i = 1; i < 4; i ++){ QueryPerformanceCounter( &lv1 ); work(q_xubober, m, q); QueryPerformanceCounter( &lv2 ); totaltime = secondsPerTick * (lv2.QuadPart-lv1.QuadPart); printf("第%d次成功运行时间= %e s \n", i, totaltime/1000000); printf("\n*************************************************************************\n"); for(j = 0; j < q_xubober; j ++) ee[i][j + 1] = q[j] + 1; } return ee; } /***********************************************************************************************/ /***********************************************************************************************/ int main(){ unsigned int i, j, k = 0, **ee = NULL; int n; printf("请输入皇后问题N的大小:\n"); scanf("%d", &n); printf("\n————————————————运行结果————————————————\n"); if(n<=3){ printf("\错误!没有解!"); exit(1); //输入小于4的数报错跳出 } if(n>=1000000000003){ printf("\错误!没有解!"); exit(1); //输入大于的数报错跳出 } ee = NQueen(n); if(n<=100){ //如果输入的n小于等于100,者输出皇后摆放位置序列,否者不输出,因为n大序列长 for(i = 1; i <=3; i++) //输出三个满足问题要求的皇后摆放位置序列try[1..3][1…n]。 { printf("\n\n第%d组解皇后摆放的位置序列位:\n",i); for(int j = 1; j < n + 1; j ++){ for(k = 1; k < n + 1; k ++){ if(k ==ee[i][j]){ //printf("%d ",k); //只输出列 printf("(%d,%d) ",j,k);} //输出行和列,第i个皇后摆放在(i,try[i]) } } } } printf("\n\n————————————————运行结果————————————————\n\n\n"); system("pause"); return 0; } /***********************************************************************************************/ // TODO (xubo18056052430#1#): PB10210016 徐波