• POJ3565 Ants 空间点对不相交匹配最小权值匹配


    题意:给定平面上两类同样多的点,要求输出一种方案使得所有匹配的点的连线两两不相交。

    解法:考虑到下面的一般情况:

    可以很容易的证明两条交叉边的距离和一定大于两条不交叉的距离和,因此问题转化为只要原图中存在交叉边,那么就可以找到更小的匹配的方式使得总距离更小。使用KM算法求出最小权值匹配输出匹配方案即可。

    代码如下:

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    int N;
    double w[105][105];
    int sx[105], sy[105];
    double lx[105], ly[105];
    double slack[105];
    int match[105];
    
    struct Node {
        int x, y;    
    }c[105], t[105];
    
    double dist(const Node &a, const Node &b) {
        return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
    }
    
    void build() {
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) {
                w[i][j] = -dist(c[i], t[j]);
            }
        }
    }
    
    int path(int u) {
        sx[u] = 1;
        for (int i = 1; i <= N; ++i) {
            if (sy[i]) continue;
            double t = lx[u] + ly[i] - w[u][i];
            if (fabs(t) < 1e-6) { // 如果这个值等于0 
                sy[i] = 1;
                if (!match[i] || path(match[i])) {
                    match[i] = u;
                    return true;    
                }
            } else {
                slack[i] = min(slack[i], t);
            }
        }
        return false;
    }
    
    void KM() {
        memset(match, 0, sizeof (match));
        fill(ly, ly+105, 0);
        fill(lx, lx+105, 0);
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) { // 为i选择一个最大的权值 
                lx[i] = max(lx[i], w[i][j]);
            }
        }
        for (int i = 1; i <= N; ++i) { // 每一次都要为i找到一条增广路
            fill(slack, slack+105, 1e30);
            while (1) {
                memset(sx, 0, sizeof (sx));
                memset(sy, 0, sizeof (sy));
                if (path(i)) break;
                double d = 1e30;
                for (int j = 1; j <= N; ++j) {
                    if (!sy[j])    d = min(d, slack[j]);
                }
                for (int j = 1; j <= N; ++j) {
                    if (sx[j]) lx[j] -= d;
                    if (sy[j]) ly[j] += d;
                    else slack[j] -= d;
                }
            }
        }
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) {
                if (match[j] == i) {
                    printf("%d\n", j);
                    break;
                }
            }
        }
    }
    
    int main() {
        while (scanf("%d", &N) != EOF) {
            for (int i = 1; i <= N; ++i)    {
                scanf("%d %d", &c[i].x, &c[i].y);
            }
            for (int i = 1; i <= N; ++i)    {
                scanf("%d %d", &t[i].x, &t[i].y);
            }
            build();
            KM();
        }
        return 0;    
    }
  • 相关阅读:
    Codeforces 787D. Legacy 线段树优化建图+最短路
    Codeforces 1051E. Vasya and Big Integers
    BZOJ3261 最大异或和
    BZOJ3531 SDOI2014 旅行
    洛谷P2468 SDOI 2010 粟粟的书架
    2018 ICPC 焦作网络赛 E.Jiu Yuan Wants to Eat
    HDU6280 From Tree to Graph
    HDU5985 Lucky Coins 概率dp
    (HDU)1334 -- Perfect Cubes (完美立方)
    (HDU)1330 -- Deck (覆盖物)
  • 原文地址:https://www.cnblogs.com/Lyush/p/3024244.html
Copyright © 2020-2023  润新知