因为和之前的翻转问题十分类似,思想就不列举了,贴上代码,供以后温故:
#include <iostream>
#include<fstream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
const int MAX = 16;
int final_step = MAX;
const int MAX_STATE = 65536;
int flips[4][4] = {4383, 8751, 17487, 34959, 4593, 8946, 17652, 35064, 7953, 12066, 20292, 36744, 61713, 61986, 62532, 63624};
struct POINT
{
int x;
int y;
};
POINT pts[MAX_STATE];
int states[MAX_STATE];
int steps[MAX_STATE];
int pres[MAX_STATE];
int qu[MAX_STATE];
int init(char str[])
{
int current_state = 0;
for(int i=0;i<MAX;i++){
if(str[i] == '+'){
current_state += (1 << i);
}
}
return current_state;
}
int flip(int state,int x,int y)
{
state ^= flips[x][y];
return state;
}
void ans(int current_state)
{
memset(steps,0,sizeof(steps));
memset(states,0,sizeof(states));
memset(pres,0,sizeof(pres));
states[current_state] = 1;
steps[current_state] = 0;
pres[current_state] = 0;
pts[current_state].x = -1;
pts[current_state].y = -1;
int front =0;
int tail = 0;
tail ++;
qu[front] = current_state;
int final_step = 0;
while(true)
{
int cur = qu[front++];
if(cur == 0)
{
break;
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
int next = flip(cur,i,j);
if(!states[next])
{
states[next] = 1;
steps[next] = steps[cur] + 1;
pres[next] = cur;
pts[next].x = i;
pts[next].y = j;
qu[tail++] = next;
}
}
}
}
cout << steps[0] <<endl;
stack<int> st;
int tmp = 0;
while(pres[tmp] != current_state)
{
st.push(tmp);
tmp = pres[tmp];
}
st.push(tmp);
while(st.size()>0)
{
cout << pts[st.top()].x + 1 <<' ' << pts[st.top()].y + 1 <<endl;
st.pop();
}
}
int main(int argc, char** argv) {
//ifstream cin("L:/test.txt");
char str[MAX];
int number = 0;
char c;
while(cin >> c)
{
if(c==' ' || c == '\n')
continue;
str[number++] = c;
if(number == 16) break;
}
int current_state = init(str);
ans(current_state);
//system("pause");
return 0;
}
主要的点在于翻转控制,毕竟BFS太简单了,而且用queue的时候会有问题,自己定义队列最好!
对于位压缩的这些常量值,整理了一下思路,写出了下面的代码,可以对照,在表中出现的值,和相应的执行代码:
/**
* 位分布图(每一位对应于原题中该位置)
* 0 1 2 3
* 4 5 6 7
* 8 9 10 11
* 12 13 14 15
*/
#include<iostream>
#include<cstdlib>
#include<vector>
using namespace std;
const int row[] = {0xF,0XF0,0XF00,0XF000};
void binary(int num)
{
vector<int> v;
int yu = num % 2;
while(num / 2)
{
yu = num % 2;
v.push_back(yu);
num = num / 2;
}
v.push_back(1);
while(v.size() <16)
{
v.push_back(0);
}
for(int i=1;i<=16;i++)
{
cout << v[i-1];
if(i % 4 == 0)
cout <<endl;
}
cout <<endl;
}
int main()
{
int state = 0;
int count = -1;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
count ++;
state = 0;
state ^= row[i];
state ^= (1 <<count);//行列交汇处异或之后复原了,要补上这一步!!!
switch(j)
{
case 0:
state ^= ((1<<0) + (1<<4) + (1<<8) +( 1<< 12));
break;
case 1:
state ^= ((1<<1) + (1<<5) + (1<<9) + ( 1<< 13));
break;
case 2:
state ^= ((1<<2) + (1<<6) + (1<<10) +( 1<< 14));
break;
case 3:
state ^= ((1<<3) + (1<<7) + (1<<11) +( 1<< 15));
break;
}
cout << count <<" : " <<state <<endl;
binary(state);
}
}
//
system("pause");
return 0;
}
binary 把每个数字对应在原图中对应的位置标识了出来,非常直观!