题解 P1219 【八皇后】

Uichiha_Itachi

2019-02-06 18:57:34

Solution

这题也算是USACO系列题目中少数几道能看得懂是什么意思的经典题了QAQ(详情请见[P2750 贰五语言](https://www.luogu.org/problemnew/show/P2750)) 看到之前的大佬们基本上用的都是记录占领哪条对角线、那条边的算法(处理一维对象),我这里就提供一种其他的方法:以点为单位处理。 以点为单位的核心就是占领、释放点的函数。 占领点: ```cpp void take(int x,int y) { grid[x][y]++;//(x,y) is taken. for(int i = 1;i <= n;i++) { grid[x][i]++;//(x,1...n),(1...n,y) is taken. grid[i][y]++; } for(int i = 1;i <= n;i++) { if(valid(x + i,y + i)) { grid[x + i][y + i]++; } if(valid(x - i,y + i)) { grid[x - i][y + i]++; } if(valid(x + i,y - i)) { grid[x + i][y - i]++; } if(valid(x - i,y - i)) { grid[x - i][y - i]++; }//Take grid points diagonally. } return; } ``` 释放点: ```cpp void release(int x,int y) { grid[x][y]--;//(x,y) is released. for(int i = 1;i <= n;i++) { grid[x][i]--;//(x,1...n),(1...n,y) is Released. grid[i][y]--; } for(int i = 1;i <= n;i++) { if(valid(x + i,y + i)) { grid[x + i][y + i]--; } if(valid(x - i,y + i)) { grid[x - i][y + i]--; } if(valid(x + i,y - i)) { grid[x + i][y - i]--; } if(valid(x - i,y - i)) { grid[x - i][y - i]--; }//Release grid points diagonally. } return; } ``` copy+pasteの杰作.jpg 如上。其中```grid```二维数组就是题目中说的棋盘的模型。 这里要注意,```grid```中使用```++,--```是有原因的: 如图:![图炸了?[看这个](https://cdn.luogu.com.cn/upload/pic/51059.png)](https://cdn.luogu.com.cn/upload/pic/51059.png) ~~配色毒瘤~~ 我们发现,若图中的绿色方格即为合法地放了皇后的方格,则图中标红的方格都由不止一个皇后占据。(实际上,这个图上的每一个没有被放皇后的点都是这样的)所以,如果我们只是用```true```,```false```两种符号标记,当回溯取走皇后时,我们就会侵♂犯其他皇后的合法权益。(蛤?)所以,我们这里采用```0```表示空格,非```0```值表示同时占有该格的皇后数。 这样,我们可以保证仅当占有一个格子的最后一个皇后被取走时,该格子才被释放。 后面的就是普通操作了,就不介绍了~~有问题出门左转洛咕网校~~。 代码:(带较详细英文注释) ``` #include <bits/stdc++.h> using namespace std; //Definitions. int n;//Size of the grid int grid[14][14];//grid map: 0 for 'empty', !=0 for 'filled'. int sol[14];//the sequence of solutions passed on in recursion. int solcnt;//number of solutions. bool valid(int,int);//check validity of gridpoint (x,y). void take(int,int);//after placeing queen(x,y), undertake grid points. void print(void);//Print solution if it is one of the first three sols. void DFS(int);//Depth first search. int main() { cin >> n; DFS(1); cout << solcnt; return 0; } bool valid(int x,int y) { if((x <= n && y <= n) && (x >= 1 && y >= 1))//In grid. { return true; } else return false; } void take(int x,int y) { grid[x][y]++;//(x,y) is taken. for(int i = 1;i <= n;i++) { grid[x][i]++;//(x,1...n),(1...n,y) is taken. grid[i][y]++; } for(int i = 1;i <= n;i++) { if(valid(x + i,y + i)) { grid[x + i][y + i]++; } if(valid(x - i,y + i)) { grid[x - i][y + i]++; } if(valid(x + i,y - i)) { grid[x + i][y - i]++; } if(valid(x - i,y - i)) { grid[x - i][y - i]++; }//Take grid points diagonally. } return; } void release(int x,int y) { grid[x][y]--;//(x,y) is released. for(int i = 1;i <= n;i++) { grid[x][i]--;//(x,1...n),(1...n,y) is Released. grid[i][y]--; } for(int i = 1;i <= n;i++) { if(valid(x + i,y + i)) { grid[x + i][y + i]--; } if(valid(x - i,y + i)) { grid[x - i][y + i]--; } if(valid(x + i,y - i)) { grid[x + i][y - i]--; } if(valid(x - i,y - i)) { grid[x - i][y - i]--; }//Release grid points diagonally. } return; } void print(void) { if(solcnt <= 3)//Make sure only print first three solutions. { for(int i = 1;i <= n;i++) { cout << sol[i] << ' '; } cout << endl; } return; } void DFS(int level) { if(level == n + 1)//Reached the end. { solcnt++;//Found a solution. print();//Print solution. return;//Backtrace. } for(int i = 1;i <= n;i++)//Try every (1...13,level). { if(valid(i,level) && (!grid[i][level]))//Valid and untaken. { sol[level] = i;//Mark as part of solution. take(i,level);//Take grid points. DFS(level);//Recurse. release(i,level);//Release grid points. sol[level] = 0;//Unmark as part of solution. } } return; } ``` (带反作弊设计) 题解终。(求过QAQ)