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;
}
posted on 2018-09-14 12:21 Iowa_Battleship 阅读(79) 评论(0) 编辑 收藏 举报