牛客多校第五场J
题意:有n颗钻石,位于三维坐标,每秒下沉vi,人每秒可捞回一棵钻石,捞回一棵钻石的代价为到原点距离的平方,问最小代价
解:肯定是0-n-1时间内捞回n颗钻石,所以是一张带权的二分图,二分图最小权匹配板子题
下附代码:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #define ll long long 5 using namespace std; 6 const int N = 305; 7 const ll inf = 1e18; 8 struct node 9 { 10 ll x, y, z, v; 11 }p[N]; 12 ll n,m,val[N][N],matched[N]; 13 ll slack[N],pre[N],ex[N],ey[N];//ex,ey顶标 14 bool visx[N],visy[N]; 15 void match(ll u) 16 { 17 ll x,y=0,yy=0,delta; 18 memset(pre,0,sizeof(pre)); 19 for(ll i=1;i<=n;i++)slack[i]=inf; 20 matched[y]=u; 21 while(1) 22 { 23 x=matched[y];delta=inf;visy[y]=1; 24 for(ll i=1;i<=n;i++) 25 { 26 if(visy[i])continue; 27 if(slack[i]>ex[x]+ey[i]-val[x][i]) 28 { 29 slack[i]=ex[x]+ey[i]-val[x][i]; 30 pre[i]=y; 31 } 32 if(slack[i]<delta){delta=slack[i];yy=i;} 33 } 34 for(ll i=0;i<=n;i++) 35 { 36 if(visy[i])ex[matched[i]]-=delta,ey[i]+=delta; 37 else slack[i]-=delta; 38 } 39 y=yy; 40 if(matched[y]==-1)break; 41 } 42 while(y){matched[y]=matched[pre[y]];y=pre[y];} 43 } 44 ll KM() 45 { 46 memset(matched,-1,sizeof(matched)); 47 memset(ex,0,sizeof(ex)); 48 memset(ey,0,sizeof(ey)); 49 for(ll i=1;i<=n;i++) 50 { 51 memset(visy,0,sizeof(visy)); 52 match(i); 53 } 54 ll res=0; 55 for(ll i=1;i<=n;i++) 56 if(matched[i]!=-1)res+=val[matched[i]][i]; 57 return res; 58 } 59 60 int main() 61 { 62 scanf("%lld",&n); 63 for (ll i = 1; i <=n; ++i){ 64 ll x, y, z, v; 65 scanf("%lld%lld%lld%lld", &x, &y, &z, &v); 66 for (ll j = 1; j <=n; ++j) 67 val[i][j]=-(x*x+y*y+(z+(j-1)*v)*(z+(j-1)*v)); 68 } 69 printf("%lld", -KM()); 70 return 0; 71 }