UVa1589 象棋

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4121

思路:找出黑将下一步可能的位置,判断该位置是否可被红方攻击。

错误1:没考虑黑将移动吃红子问题

错误2:没考虑给出的输入黑将可以直接杀红帅

错误3:输入字符问题(可能OJ系统输入有问题,总是导致超时)。

代码实现:

#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
#include<cstdio>

using namespace std;

struct Pos{
	int x;
	int y;
	bool operator<(const Pos& pt)const{
		if(this->x != pt.x)
			return this->x < pt.x;
		else
			return this->y < pt.y;
	}
	bool operator==(const Pos& pt)const{
		if(this->x == pt.x && this->y == pt.y)
			return true;
		else
			return false;
	}
};
int check[12][12];	//棋盘位置是否有棋子 
void CheckClear()
{
	for(int i = 0; i < 12; ++i)
		for(int j = 0; j < 12; ++j)
			check[i][j] = 0;
}

//俩位置之间的棋子数 
int PiecesCt(Pos& Ori, Pos& Des)
{
	int ct = 0;
	if(Ori.x == Des.x){
		int from = min(Ori.y,Des.y);
		int to = max(Ori.y,Des.y);
		for(int i = from+1; i <to;++i)
			ct += check[Ori.x][i];
	} 
	if(Ori.y == Des.y){
		int from = min(Ori.x,Des.x);
		int to = max(Ori.x,Des.x);
		for(int i = from+1; i < to; ++i)
			ct += check[i][Ori.y];
	}
	return ct;
}
//位置Ori的红棋子type是否可攻击位置Des 
bool IsHit(char type, Pos& Ori, Pos& Des) 
{
	if(type == 'G'){	//红将 
		if(Ori.y == Des.y && PiecesCt(Ori,Des)==0)
			return true;
		else
			return false;
	}
	else if(type == 'R'){	//红车 
		if((Ori.y == Des.y ^ Ori.x == Des.x) && PiecesCt(Ori,Des)==0)
			return true;
		else
			return false;		
	}
	else if(type == 'C'){	//红炮 
		if((Ori.y == Des.y ^ Ori.x == Des.x) && PiecesCt(Ori,Des)==1)
			return true;
		else
			return false;				
	}
	else if(type == 'H'){	//红马 
		int dx = Ori.x - Des.x;
		int dy = Ori.y - Des.y;
		if(dx == 1 && dy == 2 && check[Ori.x][Ori.y-1]==0)
			return true;
		else if(dx == 2 && dy == 1 && check[Ori.x-1][Ori.y]==0)
			return true;
		else if(dx == 2 && dy == -1 && check[Ori.x-1][Ori.y]==0)
			return true;
		else if(dx == 1 && dy == -2 && check[Ori.x][Ori.y+1]==0)
			return true;
		else if(dx == -1 && dy == -2 && check[Ori.x][Ori.y+1]==0)
			return true;
		else if(dx == -2 && dy == -1 && check[Ori.x+1][Ori.y]==0)
			return true;
		else if(dx == -2 && dy == 1 && check[Ori.x+1][Ori.y]==0)
			return true;
		else if(dx == -1 && dy == 2 && check[Ori.x][Ori.y-1]==0)
			return true;
		else
			return false;
	}
	
}
bool Hitable(Pos& pt,multimap<char,Pos>& redps)
{
	bool flag = false;
	for(multimap<char,Pos>::iterator it = redps.begin(); it != redps.end(); ++it){
		if(pt == it->second)
			continue;
		if(IsHit(it->first,it->second,pt)){
			flag = true;
		}
	}
	return flag;
}

int readchar(){
	for(;;){
		int ch = getchar();
		if(ch != '\n' && ch != '\r' && ch != ' ')
			return ch;
	}
} 
int main()
{
//	freopen("output.txt","w",stdout);
	//初始化黑将的初始位置 v 下一个可能位置的映射 
	map<Pos,vector<Pos>> genexts{{{1,4},{{1,5},{2,4}}},
								 {{1,5},{{1,4},{1,6},{2,5}}},
								 {{1,6},{{1,5},{2,6}}},
								 {{2,4},{{1,4},{2,5},{3,4}}},
								 {{2,5},{{1,5},{2,4},{2,6},{3,5}}},
								 {{2,6},{{1,6},{2,5},{3,6}}},
								 {{3,4},{{2,4},{3,5}}},
								 {{3,5},{{2,5},{3,4},{3,6}}},
								 {{3,6},{{2,6},{3,5}}}
								};
	
	int N;
	Pos genp;
	scanf("%d%d%d",&N,&genp.x,&genp.y);		
	while(N || genp.x || genp.y){
		CheckClear();
		//输入N个红子位置
		multimap<char,Pos> redps;
		while(N--){
			char c;
			c = readchar();
			Pos pt;
			scanf("%d%d",&pt.x,&pt.y);		
			redps.insert({c,pt});
			check[pt.x][pt.y] = 1;
		}

		bool flag = false;	//flag表示不能checkmate
		if(IsHit('G',redps.find('G')->second,genp)) {
			flag = true;
		}
		else{	
			vector<Pos> genext = genexts[genp];//黑将下一次可能的位置 
			for(int i = 0; i < genext.size(); ++i){
				if(!Hitable(genext[i],redps)){	//如果该位置不可攻击 
					flag = true;
					break;
				}
			} 
		}
		
		printf("%s\n",flag?"NO":"YES");
		
		scanf("%d%d%d",&N,&genp.x,&genp.y);
	}
	return 0;
} 

总结:刚开始提交时总是超时,然后上uDebug找输入实例调试,找出错误1和2,已经可以通过1000个输入实例,但还是超时,看网友博客后,将readchar()函数中增加了ch!=' '的条件后AC。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值