【(智慧的)模拟】中山纪念中学暑期游Day5——数码问题

前言

自己的方法应该没错来着...时间不够,考试时没调出来

题目

 Alice有一个N*N的格子,把1-N^2按照从上到下从左到右的顺序填进表格中,允许在表格上进行两种操作:
  (1) 旋转行——这一行的数向右移动一个位置,而最后一列的数会移到第一列;
  (2) 旋转列——这一列的数向下移动一个位置,最后一行的数会移到第一行。
  Alice想把数X移到(R,C)处可以采用以下方法:
  •如果X不在C这一列,通过旋转行操作把X移到C这一列;
  •如果X不在R这一行,通过旋转列操作把X移到R这一行。
  下面是一个把6移到(3,4)的例子:
  
  Alice现在想采用上述方法,依次把K个数移到各自的目标位置,编程计算每个数需要几次操作。

Input

  第一行包含两个整数N(12<=N<=10000)和K(1<=K<=1000)。
  接下来K行,每行包含三个整数X(1<=X<=N^2)、R和C(1<=R,C<=N),描述需要移动的数以及目标位置。
  Alice必须按照输入顺序依次移动。

Output

  输出K行,每行输出一个整数,表示操作次数。

Sample Input

输入1:
4 1
6 3 4

输入2:
4 2
6 3 4
6 2 2

输入3:
5 3
1 2 2
2 2 2
12 5 5

Sample Output

输出1:
3

输出2:
3
5

输出3:
2
5
3

分析

思路:每次移动数字时,实际是行和列的移动,把同在需要移动的行、列上的被询问的数也跟着移动即可

考试时奇奇怪怪的做法

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e4;
int r[MAXN+5],c[MAXN+5];//行、列的移动情况 
int n,k,a,dx,dy,x,y;
int ans1,ans2;
void Solve()
{
	//先求原始坐标 
	int t=a,rest=a;
	t/=n,rest%=n;
	if(rest!=0)
		t++;
	else
		rest=n;
	x=t,y=rest;
	//printf("*%d:%d %d\n",a,x,y);
	//printf("change:%d %d\n",c[y],r[x]);	
	int tx=x,ty=y;
	x+=c[ty],y+=r[tx];
	//printf("^%d:%d %d\n",a,x,y);
	x=(x+n)%n,y=(y+n)%n;
	if(!x) x=n;
	if(!y) y=n;
	//printf("*%d:%d %d\n",a,x,y);
	if(x<=dx)
		ans1=dx-x,c[y]-=x-dx;
	else
		ans1=n-x+dx,c[y]-=x-dx;
	if(y<=dy)
		ans2=dy-y,r[x]+=dy-y;
	else
		ans2=n-y+dy,r[x]-=y-dy;
}
int main()
{
	scanf("%d%d",&n,&k);
	while(k--)
	{
		scanf("%d%d%d",&a,&dx,&dy);
		Solve();
		printf("%d\n",ans1+ans2);
	}
	return 0;
}
/*
感觉重点是确定数a的位置... 
要点:特判一下尾数的情况 
*/

AC代码

注意:

1.第一次行的移动后,数x已经移动到了dy列上,所以代值也要代dy

2.超过n要取余

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e4;
int dx[MAXN+5],dy[MAXN+5];
int n,k;
struct node
{
	int num,x,y;
}a[MAXN+5];
void move1(int id,int y,int d)//y列上下移动
{
	for(int i=id+1;i<=k;i++)
	{
		if(a[i].y==y)
		{
			a[i].x+=d;
			a[i].x%=n;
			if(a[i].x==0)
				a[i].x=n;
		}
	}
}
void move2(int id,int x,int d)//x行左右移动
{
	for(int i=id+1;i<=k;i++)
	{
		if(a[i].x==x)
		{
			a[i].y+=d;
			a[i].y%=n;
			if(a[i].y==0)
				a[i].y=n;
		}
	}
}
void Cal(int i,int num)
{
	int t=num,rest=num;
	t/=n,rest%=n;
	if(rest!=0)
		t++;
	else
		rest=n;
	a[i].x=t,a[i].y=rest;
}
int Solve(int id,int dx,int dy)
{
	int ans1=0,ans2=0;
	int x=a[id].x,y=a[id].y;
	//该数左右移动,实际是x行左右移动
	if(y<=dy)
		ans2=dy-y,move2(id,x,dy-y);
	else
		ans2=n-y+dy,move2(id,x,n-y+dy);
	//该数上下移动,实际是y列上下移动
	if(x<=dx)
		ans1=dx-x,move1(id,dy,dx-x); 
	else
		ans1=n-x+dx,move1(id,dy,n-x+dx);
	return ans1+ans2;
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=k;i++)
	{
		scanf("%d%d%d",&a[i].num,&dx[i],&dy[i]);
		Cal(i,a[i].num);//计算初始位置 
	}
	for(int i=1;i<=k;i++)
		printf("%d\n",Solve(i,dx[i],dy[i]));
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值