小结:剪枝优化,Ologn枚举
代码1 枚举1个倍数,贪心判C
nlogn
枚举A的值
枚举A的j倍->算B
计算C: C有两种方案以保证开销最小上限和下限(尽可能靠近"新B的倍数")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
/*
nlogn
枚举A的值
枚举A的j倍->算B
计算C: C有两种方案以保证开销最小上限和下限(尽可能靠近"新B的倍数")
*/
int t;
int a,b,c;
int main(){
cin>>t;
while(t--){
cin>>a>>b>>c;
int ansA = b,ansB = b,ansC = b;
int ans = abs(b - a) + abs(c - b);
for(int A=1;A<=20015;A++){ //枚举A的值
for(int j=1;j*A<=20015;j++){ //枚举A的j倍
int B = A*j;
int C1 = c/B*B; //计算C
int C2 = (c/B+1)*B;
if(abs(a-A) + abs(B-b) + abs(C1-c) <= ans){
ansA = A,ansB = B,ansC = C1;
ans = abs(a-A) + abs(B-b) + abs(C1-c);
}
if(abs(a-A) + abs(B-b) + abs(C2-c) <= ans){
ansA = A,ansB = B,ansC = C2;
ans = abs(a-A) + abs(B-b) + abs(C2-c);
}
}
}
cout<<ans<<endl;
cout<<ansA<<" "<<ansB<<" "<<ansC<<endl;
}
return 0;
}
/*
8
1 2 3
123 321 456
5 10 15
15 18 21
100 100 101
1 22 29
3 19 38
6 30 46
*/
代码2 枚举2个倍数
#include <iostream>
using namespace std;
typedef long long ll;
int main(){
int t;
cin>>t;
while(t--){
int a,b,c;
cin>>a>>b>>c;
int ans = abs(a-b)+abs(c-b);
int mydata = b,mydatb = b,mydatc = b;
for(int A = 1;A<=20005;A++){ //枚举新的值A O(nlogn)
for(int j = 1;A*j<=20005;j++){ //枚举A的倍数 B
for(int k = 1;A*j*k<=20005;k++){ //枚举B的 倍数C
int t = abs(a-A)+abs(b-A*j)+abs(c-A*j*k);
if(ans>t){
ans = t;
mydata = A;
mydatb = A*j;
mydatc = A*j*k;
}
}
}
}
printf("%d
",ans);
cout<<mydata<<" "<<mydatb<<" "<<mydatc<<endl;
}
return 0;
}
代码3 枚举2个倍数 + 剪枝优化
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const int N = 2e5 + 10;
// 枚举的时候剪枝 ++ 变成 +倍数
int main(){
int t, a, b, c;
scanf("%d", &t);
while(t--){
scanf("%d%d%d", &a, &b, &c);
int ans = inf;
int A, B, C;
for(int i = 1; i <= 15000; ++i){
for(int j = i; j <= 15000; j += i){ //剪枝 因为成倍数关系 +=i 越后面速度速度快
for(int k = j; k <= 15000; k += j) { //剪枝 因为成倍数关系
int tmp = abs(a - i) + abs(b - j) + abs(c - k);
if(ans > tmp){
ans = tmp;
A = i;
B = j;
C = k;
}
}
}
}
cout<<ans<<'
';
cout<<A<<' '<<B<<' '<<C<<'
';
}
return 0;
}