枚举——POJ2965

来源:互联网 发布:数据库substr 编辑:程序博客网 时间:2024/06/08 19:10

POJ2965


/*Amazing!************************************************************算法原理:设'+'出现在位置(i,j)对于除去{(i,j)+(i,:)+(:,j)}的开关每个被翻转2次;对于{(i,:)+(:,j)}上的开关每个被同行(同列)翻转4次;对于(i,j)上的开关被翻转7次(在实现过程中是(8-1)次);这样,偶数次的输出为开关不变化,只有奇数次才会有翻转的效果!Notice:只对偶数*偶数(此题为4*4)的矩阵成立!************************************************************实现:1)初始化一个handle矩阵,初值为0。2)在输入的过程中,一旦有'+'(即'closed'状态)①handle{(i,:)+(:,j)}++;②handle(i,j)--,减去的是二重循环中重复计算的(i,j)位置的值3)完成输入之后,handle[4][4]上每个位置的计算次数已经确定,出现奇数次的位置即为所需翻转的位置,出现的总的次数和即为步骤!Notice:因为所需是输出的总效果,位置的次序不重要.*************************************************************/#include<iostream>using namespace std;int handle[4][4];int main(){cout << "'+' represents 'closed' while '-' represents 'opened'\n"<< "Please enter the matrix:\n";char ch;for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){cin >> ch;if ('+' == ch){for (int k = 0; k < 4; k++){handle[i][k]++;handle[k][j]++;}handle[i][j]--;//substract the repeated adding in position [i][j]}}}int sum = 0;for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)sum += handle[i][j] % 2;//if (handle[i][j] % 2)cout << sum << endl;//sum++;for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++){if (handle[i][j] % 2)cout << i << ' ' << j << endl;}}




常规的BFS+Bit+路径回溯


/*****************************************************************算法原理:路径的回溯:①记录父状态的索引,一层一层(洋葱表示不服)的追溯②记录改变的位置坐标BFS:通过Queue实现****************************************************************实现1)定义bitset<16>数组,实现flip功能,因为翻转状态有限又方便  表示。  定义Path结构体{step,father,branch},主要用于回溯。  ·step可以用来判断是否已经查找过此路径;  ·father记录父状态的index;  ·branch记录位置; (branch就像一个父状态发散的分支)  定义2^16个Path结构体,对应与POJ1753的step[65536]、flag[65536];  定义queue<bitset<16>> state 用于BFS;  Notice:初始化值最好设为-1。2)初始化输入,将'+'置为0,'-'置为1;  将初始状态压入queue3)BFS算法  Notice:注意recordPath状态的改变  ·recordPath[c].step = recordPath[p].step + 1;  ·recordPath[c].branch = i;  ·recordPath[c].father = prePiece.to_ulong();4)回溯路径。在while循环中一直追踪父状态,直到step为0即起始状态时。  因为题目的输出要去坐标,只需要将branch(坐标)压入栈就好。5)打印坐标,Get!****************************************************************  */#include<iostream>#include<bitset>#include<queue>#include<stack>using namespace std;const bitset<16> Flip[16] = {0x111f, 0x222f, 0x444f, 0x888f,//加上常量限定好习惯0x11f1, 0x22f2, 0x44f4, 0x88f8,//行列的翻转用flip数组比 判断条件的函数调用方便一点0x1f11, 0x2f22, 0x4f44, 0x8f88,//注意数组下标与bitset的高低位关系15 14 13 12 ...3 2 1 00xf111, 0xf222, 0xf444, 0xf888};struct Path{int step = -1;int father = -1;int branch = -1;//记录发生翻转的位置,才能输出坐标};Path recordPath[65536];queue<bitset<16>> state;stack<int> path;//如果必须要从初始状态开始输出坐标void Initialize(){cout << "Please enter 4*4 rectangle while '+' represents 'closed'"<< " and '-' represents 'opened':\n";char ch;bitset<16> temp;temp.set();//将Bitset中的位全置为1for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++){cin >> ch;if ('+' == ch)temp.reset(i * 4 + j);//将出现'+',即'关闭'状态置为0}state.push(temp);recordPath[temp.to_ulong()].step++;//涉及到searchPath()中何时停止入栈的判断}bitset<16> breadFirstSearch(){while (!state.empty()){bitset<16> prePiece = state.front();state.pop();int p = prePiece.to_ulong();for (int i = 0; i < 16;i++){ bitset<16>curPiece = prePiece^Flip[i];int c = curPiece.to_ulong();//不用在if-else里反复调用to_ulong函数if (prePiece.count() == 16){return prePiece;}else if (recordPath[c].step == -1)//没有尝试过过此路径时{state.push(curPiece);recordPath[c].step = recordPath[p].step + 1;recordPath[c].branch = i;//记录改变的坐标recordPath[c].father = prePiece.to_ulong();}}}return -1;}void searchPath(bitset<16> piece){int i = piece.to_ulong();path.push(recordPath[i].branch);cout << recordPath[i].step << endl;while (1){bitset<16> temp = recordPath[i].father;int t = temp.to_ulong();if (!recordPath[t].step)break;i = t;path.push(recordPath[t].branch);}}int main(){Initialize();searchPath(breadFirstSearch());while (!path.empty()){int pos = path.top();path.pop();cout << pos % 4 << ' ' << pos / 4 << endl;}}


0 0