1. 程式人生 > >POJ2965解題報告(BFS,位壓縮)

POJ2965解題報告(BFS,位壓縮)

因為和之前的翻轉問題十分類似,思想就不列舉了,貼上程式碼,供以後溫故:

#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 把每個數字對應在原圖中對應的位置標識了出來,非常直觀!