POJ 3565 Ants(二分图最小权完备匹配)

来源:互联网 发布:淘宝虚拟物品货源 编辑:程序博客网 时间:2024/06/07 10:19

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

思路:构造一个二分图,黑点白点之间的边的权值为两点的欧几里得距离,那么问题就转化为了求二分图的最小权匹配。这是因为如果最小权匹配有两条线段相交,那么一定可以转化为两条不相交且总长度更短的两条线段,这与最小权矛盾,所以可以证明最小权匹配中没有相交的线段。

#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<iostream>#include<algorithm>#include<vector>#include<map>#include<queue>#include<stack>#include<string>#include<map>#include<set>#include<ctime>#define eps 1e-4#define LL long long#define pii pair<int, int>//#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;const int MAXN = 110;const double INF = 1e17;int n, N, M;double g[MAXN][MAXN], lx[MAXN], ly[MAXN];int linky[MAXN];double slack[MAXN];bool visx[MAXN], visy[MAXN];bool dfs(int x){    int y;    visx[x] = true;    for(y = 0; y < N; y++)    {        if(visy[y]) continue;        double t = lx[x] + ly[y] - g[x][y];        if(fabs(t) < eps)        {            visy[y] = true;            if(linky[y]==-1 || dfs(linky[y]))            {                linky[y] = x;                return true;            }        }        else        {            slack[y] = min(slack[y], t);        }    }    return false;}int KM(){    double res = 0;    memset(linky, -1, sizeof(linky));    for(int i = 0; i < N; i++) ly[i] = 0;    for(int i = 0; i < M; i++)    {        lx[i] = -INF;        for(int j = 0; j < N; j++)        {            lx[i] = max(lx[i], g[i][j]);        }    }    int x;    for(x = 0; x < M; x++)    {        for(int i = 0; i < N; i++)            slack[i] = INF;        while(true)        {            memset(visx, 0, sizeof(visx));            memset(visy, 0, sizeof(visy));            if(dfs(x)) break;            double min_slack = INF;            for(int i = 0; i < N; i++)            {                if(!visy[i]) min_slack = min(min_slack, slack[i]);            }            for(int i = 0; i < M; i++)            {                if(visx[i]) lx[i] -= min_slack;            }            for(int i = 0; i < N; i++)            {                if(visy[i]) ly[i] += min_slack;            }        }    }    for(int i = 0; i < N; i++)        if(linky[i] != -1) res += g[linky[i]][i];    return res;}struct Point{    double x, y;} ant[MAXN], apple[MAXN];int main(){    //freopen("input.txt", "r", stdin);while(cin >> n)    {        N = M = n;        for(int i = 0; i < n; i++) scanf("%lf%lf", &ant[i].x, &ant[i].y);        for(int i = 0; i < n; i++) scanf("%lf%lf", &apple[i].x, &apple[i].y);        for(int i = 0; i < n; i++)        {            for(int j = 0; j < n; j++)                g[j][i] = -sqrt((ant[i].x-apple[j].x)*(ant[i].x-apple[j].x) + (ant[i].y-apple[j].y)*(ant[i].y-apple[j].y));        }        KM();        for(int i = 0; i < n; i++)            printf("%d\n", linky[i]+1);}    return 0;}

0 0
原创粉丝点击