2021牛客暑期多校训练营5 J(二分图最大权匹配KM)
作者:互联网
题目大意:
n ( n ≤ 300 ) n(n\le300) n(n≤300)个点在三维坐标系,获取某个点的代价为原点到该点的距离平方,未被获取的点每经过 t t t秒,纵坐标会增加 t ∗ v i t*v_i t∗vi
解题思路:
- n n n才300,直接建立二分图,一边是时间(0~n-1),一边是点,边权即为代价,跑KM即可
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl "\n"
const int maxn = 3e2 + 10;
using namespace std;
typedef long long ll;
ll sqr(ll x) {return x * x;}
typedef pair<int, int> pii;
int n;
struct Point {
int x, y, z, v;
} p[maxn];
namespace KM {
int vb[maxn], mb[maxn], p[maxn];
ll ka[maxn], kb[maxn], c[maxn];
ll g[maxn][maxn];
const ll inf = 1e18;
void bfs(int u) {
int a, v = 0, vl = 0;
ll d;
for (int i = 1; i <= n; i++) p[i] = 0, c[i] = inf;
mb[v] = u;
do {
a = mb[v], d = inf, vb[v] = 1;
for (int b = 1; b <= n; b++) {
if (!vb[b]) {
if (c[b] > ka[a] + kb[b] - g[a][b])
c[b] = ka[a] + kb[b] - g[a][b], p[b] = v;
if (c[b] < d) d = c[b], vl = b;
}
}
for (int b = 0; b <= n; b++)
if (vb[b]) ka[mb[b]] -= d, kb[b] += d;
else c[b] -= d;
v = vl;
} while (mb[v]);
while (v) mb[v] = mb[p[v]], v = p[v];
}
ll solve() {
memset(mb, 0, sizeof(mb));
memset(ka, 0, sizeof(ka));
memset(kb, 0, sizeof(kb));
for (int a = 1; a <= n; a++) {
memset(vb, 0, sizeof(vb));
bfs(a);
}
ll res = 0;
for (int b = 1; b <= n; b++) res += g[mb[b]][b];
return res;
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> p[i].x >> p[i].y >> p[i].z >> p[i].v;
for (int t = 1; t <= n; t++)
for (int i = 1; i <= n; i++)
KM::g[t][i] = -sqr(p[i].x) - sqr(p[i].y) - sqr(p[i].z + 1ll * (t - 1) * p[i].v);
cout << abs(KM::solve()) << endl;
}
标签:kb,vb,int,ll,多校,牛客,maxn,2021,ka 来源: https://blog.csdn.net/weixin_45691711/article/details/119416183