构造/sgu109 Magic of David Copperfield II
题意
给出一个n*n的棋盘,现有游戏规则如下:
玩家一开始在左上角的格子里,魔术师给出多条指令,每条指令包含两个信息:
1、玩家走的步数(>=n,且不重复)
2、魔术师要删除的格子
魔术师可以删除一些这一步走不到的格子,并继续发出指令,知道所有格子(除了一个)被删除,并且玩家被逼到了这个格子中。
求发出指令的一组可行方案
分析
不难发现,第一条指令肯定是让玩家走n步,之后步数逐渐增加
我们可以将这个棋盘像国际象棋棋盘那样,黑白染色
易证,走奇数步时会走到另一种颜色上,所以我们只需要每次让玩家走到另一种颜色上去,把相反颜色的格子删掉
但是这样删有两点问题:1、如果一开始n就为偶数,那么怎么走
2、删相反色的格子时,会形成“断路”,把玩家困在某些地方,而其他的格子未被删除
首先,第一点很好处理,如果为偶数,则先把周围一圈走不到的格子删掉,然后+1,把偶数转换为奇数,继续做
至于第二点,则是这道题的核心:如何删除格子?
我们知道,全删了肯定不行,那么,只需要像剥皮一样,一圈一圈地删除,那么就能把玩家困在中间某个格子里了
具体实现:
首先,先走n步,把大于与左上角曼哈顿距离的格子删掉,因为这些格子是达不到的
曼哈顿距离:横坐标之差+纵坐标之差
然后就要处理奇偶性了:如果为偶数,则+1,转换为奇数;否则+2
设一个dist为每次的曼哈顿距离与当前点的差。一层一层向里删除格子,知道这个差dist<=2,游戏结束,玩家已经被困在中间格子内。
Accepted Code
1 /* 2 PROBLEM:sgu109 3 AUTHER:Rinyo 4 MEMO:曼哈顿距离 构造 5 */ 6 7 #include<cstdio> 8 int n; 9 int main() 10 { 11 scanf("%d",&n); 12 printf("%d",n); 13 14 for (int i=1;i<=n;i++) 15 for (int j=1;j<=n;j++) 16 if (i-1+j-1>n) printf(" %d",(i-1)*n+j); 17 printf("\n"); 18 19 int dist=n+2; 20 int now=n; 21 while (dist>2) 22 { 23 now++; 24 while (now%2==0) now++; 25 printf("%d",now); 26 for (int i=1;i<=n;i++) 27 for (int j=1;j<=n;j++) 28 if (i+j==dist) printf(" %d",(i-1)*n+j); 29 printf("\n"); 30 dist--; 31 } 32 }