Statement
在半径为
r
r
r的圆中塞进
n
n
n个人,使他们两两相距最远,求最远距离
CF原题
Solution
可以用玄学的模拟退火
正常一点,我们考虑
D
P
DP
DP
n
n
n个点距离和为
∑ i = 1 n ∑ j = 1 n ( x i − x j ) 2 + ( y i − y j ) 2 \sum_{i=1}^n\sum_{j=1}^n(x_i-x_j)^2+(y_i-y_j)^2 ∑i=1n∑j=1n(xi−xj)2+(yi−yj)2
由于减法难维护,我们考虑化成加法
( a − b ) 2 = a 2 + b 2 − 2 a b \,\,\,\,\,\,(a-b)^2=a^2+b^2-2ab (a−b)2=a2+b2−2ab
( a − b ) 2 + ( b − c ) 2 + ( a − c ) 2 \,\,\,\,\,\,(a-b)^2+(b-c)^2+(a-c)^2 (a−b)2+(b−c)2+(a−c)2
= 2 ( a 2 + b 2 + c 2 ) − 2 a b − 2 b c − 2 a c =2(a^2+b^2+c^2)-2ab-2bc-2ac =2(a2+b2+c2)−2ab−2bc−2ac
=
3
(
a
2
+
b
2
+
c
2
)
−
(
a
+
b
+
c
)
2
=3(a^2+b^2+c^2)-(a+b+c)^2
=3(a2+b2+c2)−(a+b+c)2
…
可以推出
∑ i = 1 n ∑ j = 1 n ( x i − x j ) 2 + ( y i − y j ) 2 \,\,\,\,\,\,\sum_{i=1}^n\sum_{j=1}^n(x_i-x_j)^2+(y_i-y_j)^2 ∑i=1n∑j=1n(xi−xj)2+(yi−yj)2
= n ∗ ∑ i = 1 n x i 2 + y i 2 − ( ∑ i = 1 n x i 2 + y i 2 ) 2 =n*\sum_{i=1}^nx_i^2+y_i^2-(\sum_{i=1}^nx_i^2+y_i^2)^2 =n∗∑i=1nxi2+yi2−(∑i=1nxi2+yi2)2
前面一项可以直接算,后面一项是勾股定理
接下来就是搬砖
D
P
DP
DP
Code
参考乐正绫大佬
#include <cstdio>
#include <vector>
#include <algorithm>
const int N=300,M=32;
using namespace std;
struct Infected{
int x,y,dis;
Infected(){}
Infected(int _x,int _y,int _d){x=_x,y=_y,dis=_d;}
bool friend operator<(Infected a,Infected b){return a.dis<b.dis;}
};
vector<Infected> vec;
int T,n,R,i,j,k,dp[10][N<<1][N<<1],ans[50][50];
int main(){
for(i=-M;i<=M;++i)for(j=-M;j<=M;++j)vec.push_back(Infected(i,j,i*i+j*j));
for(i=0;i<=8;++i)for(j=0;j<2*N;++j)for(k=0;k<2*N;++k)dp[i][j][k]=-2e9;
sort(vec.begin(),vec.end());
register int s=0;
dp[0][N][N]=0;
for(register int r=1;r<=30;++r){
while(vec[s].dis<=r*r){
for(i=1;i<=8;++i)for(j=N-r*i;j<=N+r*i;++j)for(k=N-r*i;k<=N+r*i;++k)
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-vec[s].x][k-vec[s].y]+vec[s].dis);
++s;
}for(i=1;i<=8;++i)for(j=0;j<N*2;++j)for(k=0;k<N*2;++k)
if(dp[i][j][k]>0)ans[i][r]=max(ans[i][r],i*dp[i][j][k]-(N-j)*(N-j)-(N-k)*(N-k));
}scanf("%d",&T);while(T--)scanf("%d%d",&n,&R),printf("%d\n",ans[n][R]);
}
探讨在固定半径的圆内放置多个点,使任意两点间距离总和最大化的算法。利用数学转换简化距离计算,采用动态规划求解,通过代码实现并分享了解决方案。
337

被折叠的 条评论
为什么被折叠?



