poj1184 聪明的打字员(BFS剪枝)

http://poj.org/problem?id=1184

用字符串s存下数字,并把光标位置做一个字符加到s末尾,用map做标记状态是否出现过,然后bfs即可。

不剪枝是过不了的,考虑的两种交换操作都不涉及到2,3,4,5位置,所以这几个位置只能通过up,down来改变。

如果这几个位置是和目标状态是不一样的,那肯定是用up,down操作是最优的,而不会执行left,right操作。

所以这几个位置只有在和目标状态一样时做left,right操作。

 

#include <iostream>

#include <map>

#include <string> 

#include <queue> 

using namespace std;

struct point

{

	int step;

	string s;

};

string e;

map<string,int> my;

queue<point> q;

int BFS(point st)

{

	point t,tt; string ss; int i;

	while(!q.empty()) q.pop();

	q.push(st);  my[st.s]=1;

	while(!q.empty())

	{

		t=q.front(); q.pop();

		

		for(ss=t.s,i=0;i<6;i++)

			if(ss[i]!=e[i]) break;

		if(i==6) return t.step;

		ss=t.s; swap(ss[0],ss[ss[6]-'0']);//Swap0:

		if(!my.count(ss))

		{

			tt.s=ss; tt.step=t.step+1;

			q.push(tt); my[ss]=1;

		}

		ss=t.s; swap(ss[5],ss[ss[6]-'0']); //Swap1

		if(!my.count(ss))

		{

			tt.s=ss; tt.step=t.step+1;

			q.push(tt); my[ss]=1;

		}

		ss=t.s; if(ss[ss[6]-'0']!='9'&&ss[ss[6]-'0']!=e[ss[6]-'0']) ss[ss[6]-'0']+=1; //Up:

		if(!my.count(ss))

		{

			tt.s=ss; tt.step=t.step+1;

			q.push(tt); my[ss]=1;

		}

		ss=t.s; if(ss[ss[6]-'0']!='0'&&ss[ss[6]-'0']!=e[ss[6]-'0']) ss[ss[6]-'0']-=1;//Down: 

		if(!my.count(ss))

		{

			tt.s=ss; tt.step=t.step+1;

			q.push(tt); my[ss]=1;

		}

		ss=t.s; 

		if(ss[6]-'0'!=0)//left

		{

			if(ss[6]!='5') //1 2 3 4位置相同才能移动光标 

			{

				if(ss[ss[6]-'0']==e[ss[6]-'0']) ss[6]-=1; 

			}

			else ss[6]-=1;

		}

		if(!my.count(ss))

		{

			tt.s=ss; tt.step=t.step+1;

			q.push(tt); my[ss]=1;

		}

		ss=t.s; 

		if(ss[6]-'0'!=5)//Right

		{

			if(ss[6]!='0') //1 2 3 4位置相同才能移动光标 

			{

				if(ss[ss[6]-'0']==e[ss[6]-'0']) ss[6]+=1; 

			}

			else ss[6]+=1;

		}

		if(!my.count(ss))

		{

			tt.s=ss; tt.step=t.step+1;

			q.push(tt); my[ss]=1;

		}	

	}

}

int main(int argc, char *argv[])

{

	point st;

	while(cin>>st.s>>e)

	{

		my.clear();

		st.s+='0'; st.step=0;

		cout<<BFS(st)<<endl;

	}

	return 0;

}


 

 

你可能感兴趣的:(poj)