跳跳棋

题目

展开
题目描述
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。

我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)

跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。

写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

输入格式
第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)

第二行包含三个整数,表示目标位置x y z。(互不相同)

输出格式
如果无解,输出一行NO。

如果可以到达,第一行输出YES,第二行输出最少步数。

输入输出样例
输入 #1复制
1 2 3
0 3 5
输出 #1复制
YES
2
说明/提示
20% 输入整数的绝对值均不超过10

40% 输入整数的绝对值均不超过10000

100% 绝对值不超过10^9

思路

不难发现每一种状态,只能发展出三种状态:

1.中间向左跳 

2.中间向右跳 

3.两边的某一个向中间跳(当然根节点状态不行)

如果把一种状态疯狂地向中间折叠,会跳到一个平衡的状态,两边再也无法向中间跳了,这个状态其实就是根,而从这个状态向外发展出去,每次都只会发展出两种,所以发现这些状态构成了一棵二叉树,只要任意两种状态都能变成相同的根节点状态,那么它们一定可以相互转化

所以问题就转化成求树上两个不同节点的距离了。

先让两个节点跳到一个相同的深度,再二分距离,让这两个节点同时向上跳,最后得出答案。

哦对了,向上跳(向内折叠)时发现可以用除法来加速,一下子可以折好大一段,没有必要每一次都是加法模拟

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=177;
ll dep1,dep2;
ll getroot(ll a,ll b,ll c,ll &dep,ll &d)
{
	ll d1=b-a,d2=c-b;
	while(d1!=d2)
	{
		if(d1<d2)
		{
			ll po=d2/d1;ll op=d2%d1;
			if(!op){dep+=po-1;d=d1;return a+d1*(po-1);}
			else dep+=po,d2=op,a+=po*d1,b+=po*d1;
		}
		else
		{
			ll po=d1/d2;ll op=d1%d2;
			if(!op){dep+=po-1;d=d2;return a;}
			else dep+=po,d1=op,b-=po*d2,c-=po*d2;
		}
	}
	dep=0;d=d1;return a;
}
void lca(ll &a,ll &b,ll &c,ll k)
{
	ll d1=b-a,d2=c-b;
	while(k)
	{
		if(d1<d2)
		{
			ll po=d2/d1;ll op=d2%d1;
			if(po>=k){a+=k*d1;b+=k*d1;if(b==c)b=a,a-=d1;return;}
			k-=po;b=c-op;a=b-d1;d2=op;
		}
		else
		{
			ll po=d1/d2;ll op=d1%d2;
			if(po>=k){c-=k*d2;b-=k*d2;if(a==b)b=c,c-=d2;return;}
			k-=po;b=a+op;c=b+d2;d1=op;
		}
	}
}
int main()
{
	ll a,b,c,x,y,z,p,q,cnt=0;
	cin>>a>>b>>c>>x>>y>>z;
	ll t1=a+b+c,t2=x+y+z,m1=max(a,max(b,c)),m2=max(x,max(y,z)),i1=min(a,min(b,c)),i2=min(x,min(y,z));
	a=i1,b=t1-m1-i1,c=m1,x=i2,y=t2-m2-i2,z=m2;
	ll pp=getroot(a,b,c,dep1,p);
	ll qq=getroot(x,y,z,dep2,q);
	if(pp!=qq||p!=q){puts("NO");return 0;}
	puts("YES");
	if(dep1<dep2)
	{
		cnt+=dep2-dep1;
		lca(x,y,z,cnt);
	}
	else if(dep1>dep2)
	{
		cnt+=dep1-dep2;
		lca(a,b,c,cnt);
	}
	ll l=0,r=min(dep2,dep1),ans=0;
	while(l<=r)
	{
		ll mid=l+r>>1;
		ll aa=a,bb=b,cc=c,xx=x,yy=y,zz=z;
		lca(aa,bb,cc,mid);
		lca(xx,yy,zz,mid);
		if(aa==xx&&bb==yy&&cc==zz)ans=2*mid,r=mid-1;
		else l=mid+1;
	}
	cout<<ans+cnt;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的HTML跳棋代码,你可以参考一下: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>跳棋</title> <style type="text/css"> td { width: 50px; height: 50px; border: 1px solid black; text-align: center; vertical-align: middle; font-size: 24px; } .red { background-color: red; color: white; } .black { background-color: black; color: white; } </style> <script type="text/javascript"> var board = []; var selected = null; var redTurn = true; var offset = [[-2, -2], [-2, 2], [2, -2], [2, 2], [-1, -1], [-1, 1], [1, -1], [1, 1]]; function initBoard() { for (var i = 0; i < 10; i++) { board[i] = []; for (var j = 0; j < 9; j++) { if (i < 5) { if ((i + j) % 2 === 0) { board[i][j] = {color: 'black', type: 'pawn'}; } else { board[i][j] = null; } } else if (i === 5) { if (j === 0 || j === 8) { board[i][j] = {color: 'black', type: 'rook'}; } else if (j === 1 || j === 7) { board[i][j] = {color: 'black', type: 'knight'}; } else if (j === 2 || j === 6) { board[i][j] = {color: 'black', type: 'bishop'}; } else if (j === 3) { board[i][j] = {color: 'black', type: 'guard'}; } else if (j === 4) { board[i][j] = {color: 'black', type: 'king'}; } else if (j === 5) { board[i][j] = {color: 'black', type: 'guard'}; } } else if (i > 5) { if ((i + j) % 2 === 0) { board[i][j] = {color: 'red', type: 'pawn'}; } else { board[i][j] = null; } } } } } function drawBoard() { var table = document.createElement('table'); for (var i = 0; i < 10; i++) { var tr = document.createElement('tr'); for (var j = 0; j < 9; j++) { var td = document.createElement('td'); if (board[i][j]) { td.className = board[i][j].color; td.innerHTML = board[i][j].type; } td.addEventListener('click', function() { var row = this.parentNode.rowIndex; var col = this.cellIndex; if (board[row][col] && board[row][col].color === (redTurn ? 'red' : 'black')) { selected = {row: row, col: col}; this.style.backgroundColor = 'yellow'; } else if (selected && canMove(selected.row, selected.col, row, col)) { move(selected.row, selected.col, row, col); selected = null; redTurn = !redTurn; drawBoard(); } }); tr.appendChild(td); } table.appendChild(tr); } document.body.appendChild(table); } function canMove(fromRow, fromCol, toRow, toCol) { var dx = toCol - fromCol; var dy = toRow - fromRow; var piece = board[fromRow][fromCol]; if (toRow < 0 || toRow > 9 || toCol < 0 || toCol > 8) { return false; } if (dx === 0 && dy === 0) { return false; } if (piece.type === 'pawn') { if (piece.color === 'red' && dy < 0) { return false; } else if (piece.color === 'black' && dy > 0) { return false; } if (Math.abs(dx) + Math.abs(dy) !== 1) { return false; } } else if (piece.type === 'rook') { if (dx !== 0 && dy !== 0) { return false; } if (dx === 0) { var step = dy > 0 ? 1 : -1; for (var i = fromRow + step; i !== toRow; i += step) { if (board[i][fromCol]) { return false; } } } else if (dy === 0) { var step = dx > 0 ? 1 : -1; for (var j = fromCol + step; j !== toCol; j += step) { if (board[fromRow][j]) { return false; } } } } else if (piece.type === 'knight') { if (Math.abs(dx) + Math.abs(dy) !== 3 || Math.abs(dx) === 0 || Math.abs(dy) === 0) { return false; } var x = fromCol + dx / 3; var y = fromRow + dy / 3; if (board[y][x]) { return false; } } else if (piece.type === 'bishop') { if (Math.abs(dx) !== Math.abs(dy)) { return false; } var stepX = dx > 0 ? 1 : -1; var stepY = dy > 0 ? 1 : -1; for (var i = fromRow + stepY, j = fromCol + stepX; i !== toRow; i += stepY, j += stepX) { if (board[i][j]) { return false; } } } else if (piece.type === 'guard') { if (piece.color === 'red' && (toRow < 7 || toCol < 3 || toCol > 5)) { return false; } else if (piece.color === 'black' && (toRow > 2 || toCol < 3 || toCol > 5)) { return false; } if (Math.abs(dx) !== 1 || Math.abs(dy) !== 1) { return false; } } else if (piece.type === 'king') { if (piece.color === 'red' && (toRow < 7 || toCol < 3 || toCol > 5)) { return false; } else if (piece.color === 'black' && (toRow > 2 || toCol < 3 || toCol > 5)) { return false; } if (Math.abs(dx) + Math.abs(dy) !== 1) { return false; } } return true; } function move(fromRow, fromCol, toRow, toCol) { board[toRow][toCol] = board[fromRow][fromCol]; board[fromRow][fromCol] = null; } window.onload = function() { initBoard(); drawBoard(); }; </script> </head> <body> </body> </html> ``` 这个代码实现了一个简单的跳棋游戏,包括棋盘的绘制、棋子的移动和规则的判断等功能。你可以将它保存为一个HTML文件,用浏览器打开后即可开始游戏。注意,这只是一个很基础的实现,如果你想要实现更多功能,比如多人对战、人机对战等,还需要进一步完善代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值