P9840 [ICPC2021 Nanjing R] Oops, It‘s Yesterday Twice More 题解

题目传送门

题目大意

有一张 n × n n\times n n×n 的网格图,每个格子上都有一只袋鼠。对于一只在 ( i , j ) (i,j) (i,j) 的袋鼠,有下面四个按钮:

  • 按钮 U:如果 i > 1 i>1 i>1,移动到 ( i − 1 , j ) (i-1,j) (i1,j),否则,原地不动;
  • 按钮 D:如果 i < n i<n i<n,移动到 ( i + 1 , j ) (i+1,j) (i+1,j),否则,原地不动;
  • 按钮 L:如果 j > 1 j>1 j>1,移动到 ( i , j − 1 ) (i,j-1) (i,j1),否则,原地不动;
  • 按钮 R:如果 j < n j<n j<n,移动到 ( i , j + 1 ) (i,j+1) (i,j+1),否则,原地不动。

每次按下按钮,都会对所有的袋鼠生效。请输出一种使得所有袋鼠最终都在 ( a , b ) (a,b) (a,b) 的操作序列,并且序列的长度小于等于 3 × ( n − 1 ) 3\times(n-1) 3×(n1)

思路

很明显,按照上述的移动方式,从一个点到另一个点的步数就是他们的曼哈顿距离。

那么,我们先要把袋鼠移到一个角上,即移动到 ( 1 , 1 ) (1,1) (1,1) ( 1 , n ) (1,n) (1,n) ( n , 1 ) (n,1) (n,1) ( n , n ) (n,n) (n,n),再由这个角移到 ( a , b ) (a,b) (a,b)

那如何保证移到步数小于等于 3 × ( n − 1 ) 3\times(n-1) 3×(n1) 呢?将袋鼠移到任何一个角上都需要 2 × ( n − 1 ) 2\times(n-1) 2×(n1) 步,所以就移到离 ( a , b ) (a,b) (a,b) 最近的一个角 ( x , y ) (x,y) (x,y)。这样就可以保证, ( x , y ) (x,y) (x,y) ( a , b ) (a,b) (a,b) 的横纵坐标之差小于 n 2 \frac{n}{2} 2n。总步数就一定小于等于 3 × ( n − 1 ) 3\times(n-1) 3×(n1) 了。

分类讨论解决问题。

代码

#include <bits/stdc++.h>
using namespace std;

template<typename T> inline void read(T &x)
{
	x = 0;
	T f = 1;char ch = getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
		{
			f = -1,ch = getchar();
			break;
		}
		ch = getchar();
	}
	while(ch>='0'&&ch<='9')
		x = (x<<3)+(x<<1)+ch-48,ch = getchar();
	x*=f;
}
template<typename T> inline T read()
{
	T x;read(x);return x;
}
template<typename T> void write(T x)
{
    if(x<0) x = -x,putchar('-');
    if(x>9) write(x/10); 
    putchar(x%10+48);
}
template<typename T> inline void writen(T x)
{
    write(x);
    putchar(10);
}
int n,a,b; 
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	read(n),read(a),read(b);
	int d1 = a+b-2,d2 = n+a-b-1,d3 = n-a+b-1,d4 = 2*n-a-b,mn = min({d1,d2,d3,d4});//处理出到四个角的距离以及最小距离
	if(d1==mn)//左上角
	{
		for(int i = 1;i<n;i++) putchar('U'),putchar('L');
		for(int i = 1;i<a;i++) putchar('D');
		for(int i = 1;i<b;i++) putchar('R');
	}
	else if(d2==mn)//右上角
	{
		for(int i = 1;i<n;i++) putchar('U'),putchar('R');
		for(int i = 1;i<a;i++) putchar('D');
		for(int i = n;i>b;i--) putchar('L');
	}
	else if(d3==mn)//左下角
	{
		for(int i = 1;i<n;i++) putchar('D'),putchar('L');
		for(int i = n;i>a;i--) putchar('U');
		for(int i = 1;i<b;i++) putchar('R');
	}
	else//右下角
	{
		for(int i = 1;i<n;i++) putchar('D'),putchar('R');
		for(int i = n;i>a;i--) putchar('U');
		for(int i = n;i>b;i--) putchar('L');
	}
	return 0;
}
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值