题目大意:
矿工捞宝石,宝石在海里,每一宝石都有一个三维坐标 ( x i , y i , z i ) (x_i,y_i,z_i) (xi,yi,zi),且以 v i v_i vi的速度下沉,因此第 i i i秒后的坐标是 ( x i , y i , z i , + ( i − 1 ) ∗ v i ) (x_i,y_i,z_i,+(i-1)*v_i) (xi,yi,zi,+(i−1)∗vi)定义抓取每个宝石的代价为当前位置到原点位置的平方,每次抓宝石都会瞬间移动(每秒一次),问抓取所有的宝石的最小代价
思路:
首先,如果要代价最小,一定要在 n n n秒内抓完所有宝石(这个很好想),我们只需要考虑抓取顺序即可,有涉及代价,所以正解就是费用流拆点,将每个宝石拆为 n n n个点,第 i i i个点代表第 i i i秒钟宝石所对应的代价(位置),然后直接跑费用流即可
建图如下:
不过,出题人有意卡费用流做法,因此,最后还得用KM来做,把边权改为负,就可以直接跑最大带权匹配了,跑出来的结果是最小带权匹配
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
#define re int
#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
using namespace std;
const int mod=1e9+7;
const int M=1e8+5;
const int N=3e6+5;//?????????? 4e8
int n,m;
int la[N],lb[N],va[N],vb[N];
int match[N],upd[N],pre[N];
int w[1005][1005];
int delta;
void bfs(int x)
{
int y=0,yy=0;
for(re i=1;i<=n;i++) pre[i]=0,upd[i]=1e18;
match[y]=x;
do
{
int u=match[y],d=1e18;
vb[y]=1;
for(re v=1;v<=n;v++) if(!vb[v])
{
if(upd[v]>la[u]+lb[v]-w[u][v]) upd[v]=la[u]+lb[v]-w[u][v],pre[v]=y;
if(upd[v]<d) d=upd[v],yy=v;
}
for(re v=0;v<=n;v++) if(vb[v]) la[match[v]]-=d,lb[v]+=d;
else upd[v]-=d;
y=yy;
}while(match[y]);
while(y) match[y]=match[pre[y]],y=pre[y];
}
int KM()
{
for(re i=1;i<=n;i++) match[i]=la[i]=lb[i]=0;
for(re x=1;x<=n;x++)
{
for(re i=1;i<=n;i++) vb[i]=0;
bfs(x);
}
int ans=0;
for(re x=1;x<=n;x++) ans+=w[match[x]][x];
return ans;
}
int dis(int x,int y,int z)
{
return x*x+y*y+z*z;
}
int x[N],y[N],z[N],v[N];
void solve()
{
cin>>n;
for(re i=1;i<=n;i++) scanf("%lld%lld%lld%lld",&x[i],&y[i],&z[i],&v[i]);
for(re i=1;i<=n;i++) for(re j=1;j<=n;j++) w[i][j]=-dis(x[j],y[j],z[j]+(i-1)*v[j]);
cout<<-KM()<<endl;
}
signed main()
{
int T=1;
// cin>>T;
for(int index=1;index<=T;index++)
{
// printf("Case %d:\n",index);
solve();
// puts("");
}
return 0;
}
/*
1
6 5
0 0 0 122 499 8888
*/