UVa 12112 - Iceman

3 篇文章 0 订阅

NOIP 临近 , 博主打算做搜索题..........


提示:

1. 本题理论上是不需要优化的 , 纯bfs就能搞定 , 所以建议大家大胆试一试

2. 白书上的h() 函数可以借鉴 , 博主的剪枝效果不大


注意: 有很多细节要注意 , 比如用魔法的时候 , 左右冰的状态一定会改变


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <algorithm>
#include <queue>
#include <set>
#include <map>

using namespace std;

int n , m;
int id(int a , int b) { return a*m+b; }

struct state
{
	string s;
	string op;
	int w , step;
	state(string s = " " , int w =0 , int step = 0):s(s),w(w),step(step){ op.clear(); }
	bool operator <(const state& b)const { return s<b.s || (s==b.s && w < b.w );  }
};

set<state> dic;

int fall(string& s)
{
	for(int i=n-1;i>=0;i--) for(int j=0;j<m;j++)
	{
		int L = id(i, j);
		if(s[L]=='@' || s[L]=='O')
		{
			int wh = L+m;
			while(wh<m*n && s[wh]=='.') wh+=m; wh-=m;
			if(L!=wh) swap(s[L], s[wh]); // note that wh might equal to L  , so swap is a good way to do the change
		}
		else if(s[L]=='[')
			for(int k=j+1;k<m;k++)
			{
				int R = id(i, k);
				if(s[R]=='X') break;
				if(s[R]==']')  // from (i,j) to (i , k)
				{
					int to = 0;
					for(int l=i+1;l<n;l++)  // check if (l , j) to (l , k) is empty
					{
						bool ok = true;
						for(int ii = j;ii<=k;ii++) if(s[id(l,ii)]!='.') { ok = false; break; }
						if(!ok) { to = l-1; break; }
					}
					if(to!=i) for(int l=j;l<=k;l++) swap(s[id(i,l)], s[id(to,l)]);
					j = k;
					break;
				}
			}
	}
	for(int i=0;i<s.size();i++) if(s[i]=='@') return i;
	return -1;
}

void linkRight(char& c)
{
	if(c==']') c = '=';
	else if(c=='O') c = '[';
}

void linkLeft(char& c)
{
	if(c=='[') c = '=';
	else if(c=='O') c = ']'; 
}

bool solveMagic(state& s , int x , int y)
{
	int the = id(x, y);
	if(s.s[the]=='X') return false;
	if(s.s[the]=='.')
	{
		if(s.s[the-1]!='.' && s.s[the+1]!='.')  s.s[the] = '=' , linkRight(s.s[the-1]) , linkLeft(s.s[the+1]);  
		else if(s.s[the-1]!='.') s.s[the] = ']' , linkRight(s.s[the-1]); 
		else if(s.s[the+1]!='.') s.s[the] = '[' , linkLeft(s.s[the+1]); 
		else s.s[the] = 'O';
	}
	else
	{	
		s.s[the] = '.';
		if(s.s[the-1]=='=') s.s[the-1] = ']';
		if(s.s[the-1]=='[') s.s[the-1] = 'O';
		if(s.s[the+1]=='=') s.s[the+1] = '[';
		if(s.s[the+1]==']') s.s[the+1] = 'O'; 
	}
	s.w = fall(s.s);
	return true;
}

bool solveMove(state& s , int k)
{
	int the = s.w+k;
	
	if(s.s[the]=='.')
		swap(s.s[s.w], s.s[the]);
	else if(s.s[the]=='O' && s.s[the+k]=='.')
	{
		int wh = the;
		while(s.s[wh+k]=='.') { wh+=k; if(s.s[wh+m]=='.') break; }
		swap(s.s[the], s.s[wh]);
	}
	else if(s.s[the-m]=='.' && s.s[s.w-m]=='.')
		swap(s.s[s.w], s.s[the-m]);
	else return false;
	s.w = fall(s.s);
	return true;
}

void printnow(string s)
{
	cout<<endl;
	for(int i=0;i<n;i++) for(int j=0;j<m;j++) cout<<s[id(i, j)]<<(j==m-1?"\n":"");
}

int main(int argc, char *argv[]) {
	
	int Case=0;
	while(cin>>n&&n&&cin>>m)
	{
		dic.clear();
		string s;
		char op;
		for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)  cin>>op , s = s+op;
		
		int S = 0 , T = 0 , tx , ty;
		for(int i=0;i<s.size();i++) if(s[i]=='@') S = i; else if(s[i]=='#') T = i , s[i]='.';
		tx = T/m; ty = T%m; 
		queue<state> q;
		q.push(state(s , S , 0));
		
		cout<<"Case "<<++Case<<": ";
		while(!q.empty())
		{
			state now = q.front() , ne;
			q.pop();
			if(now.w==T) { cout<<now.op; break; }
			int x = now.w/m;
			int y = now.w%m;
			if(abs(y-ty)+now.step>15) continue;  
			ne = now;
			if(solveMagic(ne, x+1, y+1))
			{
				ne.op.push_back('>');
				ne.step++;
				if(dic.count(ne)==0) 
				{
					dic.insert(ne);
					q.push(ne);
				}
			}
			
			ne = now;
			if(solveMagic(ne, x+1, y-1))
			{
				ne.op.push_back('<');
				ne.step++;
				if(dic.count(ne)==0) 
				{
					dic.insert(ne);
					q.push(ne);
				}
			}
			
			ne = now;
			if(solveMove(ne, -1))
			{
				ne.op.push_back('L');
				if(dic.count(ne)==0) 
				{
					dic.insert(ne);
					q.push(ne);
				}
			}
			
			ne = now;
			if(solveMove(ne, +1))
			{
				ne.op.push_back('R');
				if(dic.count(ne)==0) 
				{
					dic.insert(ne);
					q.push(ne);
				}
			}
		}
		cout<<endl; 
	}
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值