网友小 Z 的树
网友小 Z 的树
对于 \(n=1\),直接返回 \((1,1)\) 即可。
对于 \(n=2\),直接返回 \((1,2)\) 即可。
对于 \(n=3\),图必为一条链,询问链的形态即可使用两次 \(2\) 操作解决。
对于 \(n=4\),询问任意三点之间答案,若为 \(\{4,4,4,6\}\) 返回 \(6\) 对应的任意两个点,若为 \(\{4,4,6,6\}\) 则返回两个 \(6\) 的公共点。
接下来我们声称能够在得出 \(n=m\) 的直径时,得出 \(n=m+3\) 时的直径。
注意到对于点集 \(S_1 + S_2\) 的直径,必然在 \(S_1\) 和 \(S_2\) 的直径端点中产生。
同时注意到 \(\dbinom{5}{2} = \dbinom{5}{3}\),我们声称每次问出原先的两个直径端点和新加的三个点之间两两距离,就可以求出两两距离,可以在 \(9\) 次内加入 \(3\) 个点。
//Ad astra per aspera
#include "diameter.h"
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
double num[20][20],ans[20];
int to_id[20][20],id[20];
pair<int,int> find_diameter(int task_id,int n){
to_id[1][2]=1;
to_id[1][3]=2;
to_id[1][4]=3;
to_id[1][5]=4;
to_id[2][3]=5;
to_id[2][4]=6;
to_id[2][5]=7;
to_id[3][4]=8;
to_id[3][5]=9;
to_id[4][5]=10;
if(n==1){
return make_pair(1,1);
}
int tot,dot_1,dot_2,len=0;
if(n==3){
tot=3;
if(in(1,2,3)){
dot_1=2;
dot_2=3;
len=2;
}
else if(in(2,1,3)){
dot_1=1;
dot_2=3;
len=2;
}
else{
dot_1=1;
dot_2=2;
len=2;
}
return make_pair(dot_1,dot_2);
}
if(n==4){
tot=4;
int ask1=query(1,2,3),ask2=query(1,2,4),ask3=query(1,3,4),ask4=query(2,3,4);
if(ask1+ask2+ask3+ask4==18){
if(ask1==6){
dot_1=1;
dot_2=2;
len=2;
}
else if(ask4==6){
dot_1=3;
dot_2=4;
len=2;
}
else{
dot_1=1;
dot_2=4;
len=2;
}
}
else{
if(ask1==6 && ask2==6){
dot_1=1;
dot_2=2;
len=3;
}
if(ask1==6 && ask3==6){
dot_1=1;
dot_2=3;
len=3;
}
if(ask1==6 && ask4==6){
dot_1=2;
dot_2=3;
len=3;
}
if(ask2==6 && ask3==6){
dot_1=1;
dot_2=4;
len=3;
}
if(ask2==6 && ask4==6){
dot_1=2;
dot_2=4;
len=3;
}
if(ask3==6 && ask4==6){
dot_1=3;
dot_2=4;
len=3;
}
}
return make_pair(dot_1,dot_2);
}
if(n==2){
tot=2;
dot_1=1;
dot_2=2;
len=1;
return make_pair(dot_1,dot_2);
}
tot=5;
id[1]=1;
id[2]=2;
id[3]=3;
id[4]=4;
id[5]=5;
memset(num,0,sizeof(num));
memset(ans,0,sizeof(ans));
int N=0;
for(int a=1;a<=5;a++){
for(int b=a+1;b<=5;b++){
for(int c=b+1;c<=5;c++){
N++;
num[N][to_id[a][b]]=1;
num[N][to_id[a][c]]=1;
num[N][to_id[b][c]]=1;
ans[N]=query(id[a],id[b],id[c]);
}
}
}
for(int i=1;i<=N;i++){
int idt;
for(int j=i;j<=N;j++){
if(num[j][i]!=0){
idt=j;
break;
}
}
for(int j=1;j<=N;j++){
swap(num[i][j],num[idt][j]);
}
swap(ans[i],ans[idt]);
double ttt=num[i][i];
for(int j=1;j<=N;j++){
num[i][j]/=ttt;
}
ans[i]/=ttt;
for(int j=i+1;j<=N;j++){
double tmp=num[j][i];
for(int k=1;k<=N;k++){
num[j][k]-=num[i][k]*tmp;
}
ans[j]-=ans[i]*tmp;
}
}
for(int i=N;i>=1;i--){
for(int j=i-1;j>=1;j--){
double ttt=num[j][i];
num[j][i]-=ttt*num[i][i];
ans[j]-=ttt*ans[i];
}
}
for(int a=1;a<=5;a++){
for(int b=a+1;b<=5;b++){
int lent=round(ans[to_id[a][b]]);
if(lent>len){
dot_1=id[a];
dot_2=id[b];
len=lent;
}
}
}
while(tot<n){
id[1]=dot_1;
id[2]=dot_2;
int pre=1;
tot++;
if(tot>n){
while(pre==dot_1 || pre==dot_2){
pre++;
}
id[3]=pre;
pre++;
}
else{
id[3]=tot;
}
tot++;
if(tot>n){
while(pre==dot_1 || pre==dot_2){
pre++;
}
id[4]=pre;
pre++;
}
else{
id[4]=tot;
}
tot++;
if(tot>n){
while(pre==dot_1 || pre==dot_2){
pre++;
}
id[5]=pre;
pre++;
}
else{
id[5]=tot;
}
memset(num,0,sizeof(num));
memset(ans,0,sizeof(ans));
N=0;
for(int a=1;a<=5;a++){
for(int b=a+1;b<=5;b++){
for(int c=b+1;c<=5;c++){
if(a==1 && b==2 && c==3){
N++;
num[N][1]=1;
ans[N]=len;
}
else{
N++;
num[N][to_id[a][b]]=1;
num[N][to_id[a][c]]=1;
num[N][to_id[b][c]]=1;
ans[N]=query(id[a],id[b],id[c]);
}
}
}
}
for(int i=1;i<=N;i++){
int idt;
for(int j=i;j<=N;j++){
if(num[j][i]!=0){
idt=j;
break;
}
}
for(int j=1;j<=N;j++){
swap(num[i][j],num[idt][j]);
}
swap(ans[i],ans[idt]);
double ttt=num[i][i];
for(int j=1;j<=N;j++){
num[i][j]/=ttt;
}
ans[i]/=ttt;
for(int j=i+1;j<=N;j++){
double tmp=num[j][i];
for(int k=1;k<=N;k++){
num[j][k]-=num[i][k]*tmp;
}
ans[j]-=ans[i]*tmp;
}
}
for(int i=N;i>=1;i--){
for(int j=i-1;j>=1;j--){
double ttt=num[j][i];
num[j][i]-=ttt*num[i][i];
ans[j]-=ttt*ans[i];
}
}
for(int a=1;a<=5;a++){
for(int b=a+1;b<=5;b++){
int lent=round(ans[to_id[a][b]]);
if(lent>len){
dot_1=id[a];
dot_2=id[b];
len=lent;
}
}
}
}
return make_pair(dot_1,dot_2);
}

浙公网安备 33010602011771号