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 把每个数字对应在原图中对应的位置标识了出来,非常直观!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值