题意:
给你一组三个互不相同的点,按照规定能不能转移到第二组的点,如果能算出最少的步数。
一个点只能移到相邻的点的对称位置,比如2 的的相邻点是 5,它可以移到8。但是这之间存在第三个点就不能移动,比如存在6, 7,就2就不能移动到8。
那么2 5 -> 5 8可以看做2移动了3个位置,5移动三个位置。
对于三个数 x, y, z一般可以有2或者三种移动方式
- y-x = z-y 的时候,只能 y 往两边移动,只有两种移动方式。
- y-x != z-y 的时候,可以移动和y距离的的那个数,往中间移动 + y往两边移动,就有三种移动方式
然后可以看做一棵二叉树,两个度的为根,三个度的为除了根以外的节点。
如果两组节点可以互相转换的要求为根节点相同,如果根节点相同,主要是找LCA。
如果一一模拟转移的话1 2 100 - >98 99 100需要很多次,可以用辗转相除的方式。
1 2 100 -> 2 3 100需要一步, 1 2 100 -> 3 4 100需要两步,1 2 100 - 98 99 100就可以一步算出来。
然后二分查找LCA就解决了。
AC代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e5+10;
struct Node{
int x[4];
}node[3], root[3];
int get_root(Node &a){ //查找根节点,返回深度
int l = a.x[2] - a.x[1], r = a.x[3] - a.x[2];
int d = 0;
while(l != r){
if(l > r){
d += l/r;
a.x[3] -= l/r*r;
a.x[2] -= l/r*r;
l %= r;
}
else if(l < r){
d += r/l;
a.x[1] += r/l*l;
a.x[2] += r/l*l;
r %= l;
}
if(l == 0){
a.x[2] += r;
a.x[3] += r;
l += r;
d--;
}
if(r == 0){
a.x[2] -= l;
a.x[1] -= l;
r += l;
d--;
}
}
return d;
}
int Equal(Node a, Node b){ //判断是否相等
int flag = 1;
for(int i = 1; i <= 3; i++){
if(a.x[i] != b.x[i])
flag = 0;
}
return flag;
}
Node change(Node a, int num){ //把a在树上向上移num次
int l = a.x[2] - a.x[1], r = a.x[3] - a.x[2];
while(num != 0){
if(l < r){
if(num > r/l){
a.x[1] += r/l*l;
a.x[2] += r/l*l;
num -= r/l;
r %= l;
}
else{
a.x[1] += l*num;
a.x[2] += l*num;
num = 0;
}
}
else{
if(num > l/r){
a.x[2] -= l/r*r;
a.x[3] -= l/r*r;
num -= l/r;
l %= r;
}
else{
a.x[2] -= num*r;
a.x[3] -= num*r;
num = 0;
}
}
}
return a;
}
int solve(Node a, Node b, int h){ //把a和b向上移h并判断是否相等
a = change(a, h);
b = change(b, h);
return Equal(a, b);
}
int lca(int deep_a, int deep_b){ //找到LCA节点,返回步数
int l , r, num = 0, m, ans = 0;
Node u = node[1], v = node[2];
if(deep_a < deep_b){
swap(u, v);
}
num = abs(deep_a - deep_b);
u = change(u, num);
if(!Equal(u, v)){
l = 1; r = min(deep_a, deep_b);
ans = r;
while(l <= r){
m = l+r>>1;
if(solve(u, v, m)){
ans = m;
r = m-1;
}
else
l = m+1;
}
}
}
int main(){
while(scanf("%d%d%d", &node[1].x[1], &node[1].x[2], &node[1].x[3]) != EOF){
sort(node[1].x+1, node[1].x+4);
root[1] = node[1];
for(int i = 2; i <= 2; i++){
for(int j = 1; j <= 3; j++){
scanf("%d", &node[i].x[j]);
}
sort(node[i].x+1, node[i].x+4);
root[i] = node[i];
}
int a, b, flag = 0;
a = get_root(root[1]);
b = get_root(root[2]);
for(int i = 1; i <= 3; i++){
if(root[1].x[i] != root[2].x[i])
flag = 1;
}
if(flag){
printf("NO\n");
continue;
}
printf("YES\n%d\n", lca(a, b));
}
return 0;
}
/*
1 3 4
0 3 5
-2 2 8
0 2 6
*/