关于捕捞所有宝物的最小消耗体力量的问题

原题链接
在岸上捕捞n(<=300)个宝物,一秒捕一个,捕捞消耗的体力为宝物的此时坐标(xi,yi,zi+t*vi)的平方,t为当前时间,求捕捞所有宝物的最小消耗体力量。
分析:
易知为二分图的带权最小匹配问题,事实上只要带有“选择”的意味的题目,都可以考虑使用二分图算法试解。
这题的难点主要在卡时间,网上的很多板子都卡了,这里给出一份跑得飞快的二分图的带权匹配的板子。

LL w[maxv][maxv];   //记录边权
bool getVal[maxv][maxv]; //记录该边是否被赋值,以上两个数组都需要在读边的时候完成赋值
namespace KM {
    long long cal(int n, int m,bool isSmall) {  //带权匹配模板,总n个点,最大匹配m个点,isSmall表示是否是最小带权匹配
        std::vector<long long> u(n + 1), v(m + 1), p(m + 1), way(m + 1);
        if(!isSmall) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) w[i][j]=-w[i][j];
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(!getVal[i][j]) w[i][j]=1e18;
        for (int i = 1; i <= n; i++) {
            p[0] = i;
            long long j0 = 0;
            std::vector<long long> minv(m + 1, 1e18);
            std::vector<char> used(m + 1, false);
            do {
                used[j0] = true;
                long long i0 = p[j0], delta = 1e18, j1;
                for (int j = 1; j <= m; ++j) {
                    if (!used[j]) {
                        long long cur = w[i0][j] - u[i0] - v[j];
                        if (cur < minv[j]) {
                            minv[j] = cur, way[j] = j0;
                        }
                        if (minv[j] < delta) {
                            delta = minv[j], j1 = j;
                        }
                    }
                }
                for (int j = 0; j <= m; ++j) {
                    if (used[j]) {
                        u[p[j]] += delta, v[j] -= delta;
                    }
                    else {
                        minv[j] -= delta;
                    }
                }
                j0 = j1;
            } while (p[j0] != 0);
            do {
                long long j1 = way[j0];
                p[j0] = p[j1];
                j0 = j1;
            } while (j0);
        }
        long long res = 0;
        for (int i = 1; i <= m; i++) {
            res += w[p[i]][i];
        }
        if(!isSmall) res=-res;
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值