牛客多校第五场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 }
View Code
原文地址:https://www.cnblogs.com/i-caigou-TT/p/15089007.html