POJ3565 Ants

原题链接

要求所有线段不相交,实际上满足每条线段的长度和最小。
所以我们可以让蚁窝和苹果树连边,边权为两点的距离,然后就是求二分图带权最小匹配了,可以上\(KM\)算法或是费用流。
这里我使用的是费用流。

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 210;
const int M = 1e5 + 10;
struct dd {
    int x, y;
};
dd a[N >> 1];
int fi[N], di[M], da[M], ne[M], q[M << 2], la[N], cn[N], l = 1, st, ed;
double dis[N], co[M];
bool v[N];
inline int re()
{
    int x = 0;
    char c = getchar();
    bool p = 0;
    for (; c < '0' || c > '9'; c = getchar())
        p |= c == '-';
    for (; c >= '0' && c <= '9'; c = getchar())
        x = x * 10 + c - '0';
    return p ? -x : x;
}
inline void add(int x, int y, int z, double c)
{
    di[++l] = y;
    da[l] = z;
    co[l] = c;
    ne[l] = fi[x];
    fi[x] = l;
}
inline int minn(int x, int y)
{
    return x < y ? x : y;
}
bool bfs()
{
    int head = 0, tail = 1, i, x, y;
    memset(dis, 66, sizeof(dis));
    q[1] = st;
    dis[st] = 0;
    while (head ^ tail)
    {
        x = q[++head];
        v[x] = 0;
        for (i = fi[x]; i; i = ne[i])
            if (da[i] > 0 && dis[y = di[i]] > dis[x] + co[i])
            {
                dis[y] = dis[x] + co[i];
                la[y] = x;
                cn[y] = i;
                if (!v[y])
                {
                    q[++tail] = y;
                    v[y] = 1;
                }
            }
    }
    return dis[ed] < 1e8;
}
int main()
{
    int i, j, x, y, n, mi;
    double d;
    n = re();
    st = n << 1 | 1;
    ed = st + 1;
    for (i = 1; i <= n; i++)
    {
        a[i].x = re();
        a[i].y = re();
    }
    for (i = 1; i <= n; i++)
    {
        x = re();
        y = re();
        for (j = 1; j <= n; j++)
        {
            d = sqrt(1.0 * (x - a[j].x) * (x - a[j].x) + 1.0 * (y - a[j].y) * (y - a[j].y));
            add(j, i + n, 1, d);
            add(i + n, j, 0, -d);
        }
    }
    for (i = 1; i <= n; i++)
    {
        add(st, i, 1, 0);
        add(i, st, 0, 0);
        add(i + n, ed, 1, 0);
        add(ed, i + n, 0, 0);
    }
    while (bfs())
    {
        mi = 1e9;
        for (i = ed; i ^ st; i = la[i])
            mi = minn(mi, da[cn[i]]);
        for (i = ed; i ^ st; i = la[i])
        {
            da[cn[i]] -= mi;
            da[cn[i] ^ 1] += mi;
        }
    }
    for (i = 1; i <= n; i++)
        for (j = fi[i]; j; j = ne[j])
        {
            y = di[j];
            if (y > n && y ^ ed && y ^ st && !da[j])
            {
                printf("%d\n", y - n);
                break;
            }
        }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Iowa-Battleship/p/9645842.html