CF 1921E

#include

using namespace std;

void solve()
{
	int h,w,xa,ya,xb,yb;
	cin>>h>>w>>xa>>ya>>xb>>yb;
	
	if(xa==xb)
	{
		cout<<"Draw"<<endl;
		return;
	}
	
	if(xa>xb)
	{
		cout<<"Draw"<<endl;
		
		return;
	}
	
	if(xb-xa==1)
	{
		if(abs(ya-yb)<=1)
			cout<<"Alice"<<endl;
		else
			cout<<"Draw"<<endl;
		
		return;
	}
	
	int cnt=0;
	int la=ya,ra=ya,lb=yb,rb=yb;
	while(xa<xb)
	{
		if(xb-xa==1)
			break;
		cnt++;
		
		if(cnt&1)
		{
			xa++;
			if(la>1)
				la--;
			if(ra<w)
				ra++;
		}
		else
		{
			xb--;
			if(lb>1)
				lb--;
			if(rb<w)
				rb++;
		}
	}
	
//	cout<
//	cout<
	
	if((cnt+1)&1)
	{
		if(la>1)
			la--;
		if(ra<w)
			ra++;
		
		if(ra>=rb&&la<=lb)
			cout<<"Alice"<<endl;
		else
			cout<<"Draw"<<endl;
	}
	else
	{
		if(lb>1)
			lb--;
		if(rb<w)
			rb++;
		
		if(rb>=ra&&lb<=la)
			cout<<"Bob"<<endl;
		else
			cout<<"Draw"<<endl;
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

做该题的时候想过很多次看题解,但是强迫自己没看题解,慢慢地想,然后改代码调试,弄了一个半小时过了

我的思路是,判断一下两个棋子只相差一行的时候的情况,维护一个左右边界,表示的是可能选择的点,假设操作的次数是奇数,表示应该轮到 A l i c e Alice Alice 下棋了,操作的次数是偶数,表示应该轮到 B o b Bob Bob 操作了

假设某一个人的下棋的区间可以完全覆盖另一个人的区间,表示这个人可以获得胜利,否则就是平局(这个可以画图来理解),假设不是完全覆盖,按照最优策略,另一个人可以选择往不被覆盖的点去操作

最优策略是根据两个棋子只相差一行的时候,轮到谁下来进行调整的

刚开始想的是用 c n t cnt cnt 表示回合数,也就是两个人各操作一次,但是我后面发现不方便,因为不能确定一定是偶数的操作次数就截止了,表示起来麻烦一些

c n t cnt cnt 表示操作的次数,边界更新的时候需要严格大于,严格小于,我是输出调试的时候发现左边界出现了 0 0 0 ,发现的这个问题,每一次操作更新边界的同时也更新行数

最后一次操作的时候更新边界,判断区间的包含关系

前面加了很多特判,比如说两个点相差一行,纵坐标之间的差的绝对值小于等于 1 1 1 的话,一定是第一个人胜利,两个点在同一行的话,一定是平局,如果不可能相交的话,也一定是平局

#include

using namespace std;

void solve()
{
	int h,w,xa,ya,xb,yb;
	cin>>h>>w>>xa>>ya>>xb>>yb;
	
	if(xa>=xb)
	{
		cout<<"Draw"<<endl;
		return;
	}
	
	int cnt=0;
	int la=ya,ra=ya,lb=yb,rb=yb;
	while(xa<xb)
	{
		if(xb-xa==1)
			break;
		cnt++;
		
		if(cnt&1)
		{
			xa++;
			if(la>1)
				la--;
			if(ra<w)
				ra++;
		}
		else
		{
			xb--;
			if(lb>1)
				lb--;
			if(rb<w)
				rb++;
		}
	}
	
	if((cnt+1)&1)
	{
		if(la>1)
			la--;
		if(ra<w)
			ra++;
		
		if(ra>=rb&&la<=lb)
			cout<<"Alice"<<endl;
		else
			cout<<"Draw"<<endl;
	}
	else
	{
		if(lb>1)
			lb--;
		if(rb<w)
			rb++;
		
		if(rb>=ra&&lb<=la)
			cout<<"Bob"<<endl;
		else
			cout<<"Draw"<<endl;
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

改成这样会更简洁一点,有一些特判其实是包含在后面的一般做法里面的,准确的来说就是思路清晰一些,代码就会简短一些,但无论如何,能通过的代码就是好代码

所以该题最难的点是,什么时候谁会获得胜利,算是一个博弈论,要么是完全覆盖,胜利,要么就是平局,部分覆盖不算赢,这一个点比较难想清楚

因为部分覆盖的话,另一个选手完全可以选择往没有覆盖的部分去走,需要走下一步的选手无法走到另一个选手的棋子上去,这一次操作过后,两个棋子错开了,一定是平局,再也没有相交的可能

总的来说,写出来这个题给我的正反馈挺强的

你可能感兴趣的:(#,1600,算法)