HihoCoder 1835 K-Dimensional Foil II ICPC2018 北京网络赛
http://www.cnblogs.com/DevilInChina/p/9691126.html
这个dalao 的思路
设平移球心到原点后 当前飞船坐标为 p(y_1,y_2,..,y_k) 球面上该点坐标q(a_1,a_2,...,a_k)
设 F(p) = sigma(yi-ai)^2 +lam*(sigema(ai) -R)
对每个ai求偏导后加起来可以得到lam ai yi 的关系式
根据关系式不断逼近最值即可
#include <bits/stdc++.h> using namespace std; #define LL long long const int maxn=1e2+10; int c[maxn]; int y[maxn]; int f[maxn]; double a[maxn]; double b[maxn]; int n,k,r; int sgn(int x) { return x>=0? 1:-1; } #define eps 1e-6 bool check() { for(int i=0;i<k;i++) { if(fabs(a[i]-b[i])>eps)return false; } return true; } void deal() { static int finish[maxn]; for(int i=0;i<k;i++) finish[i]=0; double lam=0; bool flag; do{ //lam=(sigma y[i] -r)/n //a[i]=y[i]-lam lam=0; int tot=0; for(int i=0;i<k;i++) if(!finish[i]) lam+=y[i],tot++; lam=(lam-r)/tot; flag=false; for(int i=0;i<k;i++) { if(finish[i])continue; a[i]=-lam+y[i]; if(a[i]<=0)a[i]=0,finish[i]=1,flag=true; } }while(flag); } void deal2() //第二种方法 不断的给这个向量各个维度等大的截断,某维度没有那么长就置0,直到这个向量的"长度"为R(这里是题目要求的欧氏距离) { static int ok[maxn]; for(int i=0;i<k;i++) ok[i]=0; double sum=accumulate(y,y+k,(double)-r); //加和过程中会把元素类型转换为init类型 bool flag=true; int tot=k; while(flag) { flag=false; double avg=sum/tot; for(int i=0;i<k;i++) printf("%.4f ",a[i]);printf("%f\n",avg); for(int i=0;i<k;i++) { if(ok[i])continue; a[i]=y[i]-avg; if(a[i]<=0) { ok[i]=1; a[i]=0; sum-=y[i]; tot--; flag=true; break; } } } } int main() { #ifdef shuaishuai freopen("in.txt","r",stdin); #endif // shuaishuai int t; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&k,&r); for(int i=0;i<k;i++) scanf("%d",c+i); while(n--) { for(int i=0;i<k;i++) { scanf("%d",y+i); f[i]=sgn(y[i]-c[i]); y[i]=abs(y[i]-c[i]); } deal2(); for(int i=0;i<k;i++) printf("%.4f%c",a[i]*f[i]+c[i],i==k-1?'\n':' '); } } return 0; }