这是2017广东工业大学程序设计竞赛决赛中的一个题目
Description
众所周知的是,TMK特别容易迟到,终于在TMK某次又迟到了之后,Maple怒了,Maple大喊一声:“我要跟你决一死战!”然后Maple就跟TMK玩起了一个关于占点的游戏。
Maple在一个无限展开的只有整数点的二维平面上找到两个点,由TMK和Maple分别操控这两个点,两人轮流操作,每一次操作中TMK或Maple可以把他的点移动一格到上、下、左、右四个方向,当TMK操作时,移动到的这个点会被染成红色,而当Maple操作时,移动到的这个点会被染成蓝色,需要注意的是,两个起始时的两个点也都会被染上相应的颜色,而当任一人走到已经染了不同颜色的点,这个颜色会被覆盖掉,当两个点覆盖在一起时,这个点会被后来的点染色。当游戏结束时染着自己颜色的点就代表被自己占领了。
TMK一下就明白了,这个游戏的目标是让自己占领的点比对方占领的点多,而且要让差值最大。
为了公平一些,Maple决定让TMK来选择先手或后手和让TMK来选择点,相应的Maple就会选择另一个点。
现在给出游戏的总轮数N,Maple选择的两个点的坐标(x1,y1),(x2,y2),要TMK来选择先后手和起始点,假设Maple一定按最优策略来走,问TMK能不能选择先后手和起始点使得自己占领的点比Maple占领的多,如果能,那么同时要求出占领的点数的最大差值。
Input
第一行一个T,代表接下来有T组数据(1<=T<=2000)。
每组数据有五个整数N,x1,y1,x2,y2,代表了操作的总轮数N以及选择的两个起始点(x1,y1),(x2,y2),其中1<=N<=10^8,-10^8<=x1,y1,x2,y2<=10^8,数据保证两个点不相同。
Output
对于每一组数据,如果TMK占领的点不能比Maple占领的多,那么输出-1,否则输出两个占领点数的最大差值。
Sample Input
1 0 0 1 0
2 0 0 1 0
1 0 0 2 0
2 0 0 2 0
Sample Output
-1
1
-1
对题闲聊:说实话这题是我做过的分支结构中的最复杂的一题(我不会告诉你们我写了一个小时的!),由于题目中的Maple都是按最优路线走的,这个解释很让人深思,所以这题的主要思路就是什么才是最优思路呢?这很重要,否则,就别想写出来这道题了,还有一个大坑,题目里所说的一轮,不是一轮两个人各走一次,而是一轮一个人走一次,说实话要是一轮两个各走一次的话,TMK就别想赢了O(∩_∩)O~(而且这样这个轮数也没什么大的意义,只能判断在有效轮数之内两个点能否接壤,,还有如果轮数为单数,TMK必须选先手,这样他就能多走一步,这样才有翻盘的机会,还有一个Maple选择问题,他必须选择是否迎战。最优走法嘛。所以需要分析棋盘的压制状况。这很重要,这直接决定了TMK是否要和Maple刚正面,如果被压制了还刚正面我就不吐槽了。
接下来给出几组案例。
我们假设1是TMK染过色的块,2是Maple染过色的块;
先看步数为奇数的时候,如果多走一步都刚不过那偶数就更没辙了。
由于Maple要走最优路线,那就必须追TMK的尾,即图中1的位置。
如果2追到了1的尾而1无法在2的相邻色块上,那必输,所以TMK
必须向Maple方向走。现在,TMK先走,如何压制?往下走,追
2的尾并且让2无法主动攻击,因为一走右边或上边就会被1染色
2只能往左或者下边走,然后这个时候1来追尾了,这个时候又出现一个问题
该往左还是往下呢?我们说了我们TMK也不是吃素的,如果Maple往左走(比如图二,2往左走了一步)
Maple肯定选择往下走一步,因为这个游戏有一个大前提:!!!!!(重点!!!!)自己 在能压制对方的情况下 染过色的块要尽量
远离敌人,以防被染色。
这样2就手足无措了,又染不到对面的,自己的又要被染色,心痛,这个时候2又要选择了,到底是往右边回去呢,还是往别的地方走呢?
他的选择必须是往回走,因为往别的地方还无法直接接触到1,就算少染一个颜色也没事,因为自己的色块一旦被占领,2的利益损失量就是2,
因为对面多了一个自己少了一个嘛,然往回走的话只会少染一个格子,损失一个颜色,所以这里就要考虑1能否追上2了,由于我们是在能走无限步数的情况下,
所以一定追的了尾,所以2必须往回走,这样的话被占了之后还能立刻占回来。
这里注意下,后文说明的追尾就是能走到对方的初始位置。!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
还有一种情况就是(有限步数的时候)1只能追到2的一个尾巴轮次就结束了,走完了,那2应该选择往别的地方跑,这样多占一个格子,因为被占了之后没有下一步了,所以2就算回去也占不过来,那还不如趁现在多占一个格子。但是这两种情况结果都是一样的,都是被1比2多两个格子,我们可以把这两种情况总结起来,原因如图三图四图五图六
情况一↓
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 2 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
2 | 2 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
图三(有限步数,1只能追到2的尾轮次就结束了,2选择走别的方向,这是结果2两个,1四个,差两个)
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
2 | 0 | 1 | 0 | 0 |
2 | 1 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
2 | 12 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
1 | 1 | 2 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
所以对长远的情况下来说肯定是往回走比较靠谱吧。。
这样的话存在距离差等于3的情况。其实还有更好的办法,后面会有讲解。
如果你们觉得当初图二的时候2应该选择往上走再往右走你们可以自己试试。
好了,最复杂的情况讲述半完毕hhhhhh。//
如果步数是偶数,Maple就不会被TMK牵制,因为就算TMK先占了,由于Maple步数和TMK相同所以他可以占回来。
同样用图一来演示1刚开始肯定往下走这个时候注意了,2并不需要退让,因为自己的步数可以TMK相同,所以就算先被
占了也可以占回来,所以TMK格子永远不会比Maple多。
↓
图七
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 2 | 1 | 0 | 0 |
0 | 2 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
现在TMK走一步之后Maple再走一步,试问怎样能让TMK占得比Maple多?
这个时候你们如果眼尖的话是不是发现了什么,这种情况就算步数是奇数的时候
最多也只亏损两个格子,所以前面图三四五的时候最少差两个格子,所以不应该逃,而是直接和1刚,这里又要考虑1的步数了,
(现在讨论的又回到奇数步数的时候了)
如果1本来追不上你,这样两者之间只差一个格子,2硬要和1刚,导致1追的上2了,那不是要差两个格子了?所以这个时候要考虑1到底能不能追上2,
追不上咱就跑,追的上咱就刚,反正最多差两个格子到顶了。
所以在1追的上2的情况下(或者说就算Maple从刚开始就跑TMK也追的上的话),这种就是最坏情况了,最多差两个格子。
追不上的话Maple就跑,就差一个格子。
(现在回到偶数步数)
就算1往左走了占了2的格子,由于两个人可以走的步数相同,所以轮次一定还没有结束,2可以往右走,两者可以持平,所以TMK永远无法比Maple格子多。
再考虑下距离差是偶数的时候,
(偶数距离,例如下图,距离为4)
比如
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 2 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
所以总结一下以上的情况,
如果是偶数步数,必败无疑(就是TMK占的格子绝对不会比Maple多)。不管追不追的到尾,距离是奇数还是偶数。
否则///奇数步数 TMK肯定先手
{
先判断距离奇偶性,这个比较重要,
{
判断距离1能否追尾2
不能的话,只能多占一个格子,
否则占能多占两个格子
}
否则,即距离为偶数
MTK无论如何无法压制Maple,前面有说明
接下来判断距离
{
追尾的上的话,TMK完蛋了
追尾不上,哈哈哈哈,由于TMK先走的,所以多占一个。
}
}
如果有人能耐着性子看到现在也不容易了,下面
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
int main()
{
int T;
scanf("%d",&T); //数据的组数
while(T--)
{
long long n;
long long x1,y1,x2,y2;
scanf("%lld%lld%lld%lld%lld",&n,&x1,&y1,&x2,&y2); //输入数据,这个就不解释了
if(n%2==0) // 判断轮数是否为偶数,偶数的话TMK就别想赢了,单数的话,TMK选先手可以多走一步。
printf("-1\n");
else
{
if(abs(x1-x2)+abs(y1-y2)%2==0) //判断两点之间的x方向上的距离和y方向上的距离之和,是否为偶数,
//因为棋盘存在压制状况,如果是偶数,那么TMK刚正面就会亏
if(abs(x1-x2)+abs(y1-y2)*2>n) //判断Maple追不追的到TMK,追不到咱就跑,正面刚不过,因为是先手所以会多一格哈哈哈
printf("1\n");
else //追的到,认输吧
printf("-1\n");
else //TMK可以压制Maple
if((abs(x1-x2)+abs(y1-y2)-1)*2>n) //Maple刚不过只能跑,检查两点间的距离,看看跑的掉不
printf("1\n"); //如果追不到,反正TMK先走的,多一步
else
printf("2\n"); //追得到,TMK人生迎来了光明
}
}
return 0;
}