UVA1411 Ants 二分匹配

本文探讨了一种使用KM算法解决蚂蚁路径问题的方法,通过将问题转化为最小权匹配问题,成功解决了不同点集连线不相交的问题。该方法不仅避免了使用费用流可能带来的时间复杂度过高的问题,还提供了矩阵存储的替代方案,使得解决方案更加高效。
摘要由CSDN通过智能技术生成

之前这种问题一直用费用流做,今天想试一下KM,结果之前的km模板被卡了。n^4的原来是。。。。果断换之。毕竟那个模板我只拿来A过一道题目。。。。。之前这类问题一直果断费用流,觉得KM的时间复杂度实在太高。而且矩阵存储是我很不喜欢的方式。
这道题是两个点集 分别n个点。不同点集连线不能相交。问最后连接方案。
转化成最小权匹配。成功解决问题。匹配的是最短距离一定不会相交。
Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu

[]   [Go Back]   [Status]  

Description

Download as PDF

Young naturalist Bill studies ants in school. His ants feed on plant-louses that live on apple trees. Each ant colony needs its own apple tree to feed itself.

Bill has a map with coordinates of n ant colonies and n apple trees. He knows that ants travel from their colony to their feeding places and back using chemically tagged routes. The routes cannot intersect each other or ants will get confused and get to the wrong colony or tree, thus spurring a war between colonies.

Bill would like to connect each ant colony to a single apple tree so that all n routes are non-intersecting straight lines. In this problem such connection is always possible. Your task is to write a program that finds such connection.

\epsfbox{p4043.eps}

On this picture ant colonies are denoted by empty circles and apple trees are denoted by filled circles. One possible connection is denoted by lines.

Input

Input has several dataset. The first line of each dataset contains a single integer number n (1$ \le$n$ \le$100) -- the number of ant colonies and apple trees. It is followed by n lines describing n ant colonies, followed by n lines describing n apple trees. Each ant colony and apple tree is described by a pair of integer coordinates x and y (- 10000$ \le$xy$ \le$10000) on a Cartesian plane. All ant colonies and apple trees occupy distinct points on a plane. No three points are on the same line.

Output

For each dataset, write to the output file n lines with one integer number on each line. The number written on i -th line denotes the number (from 1 to n ) of the apple tree that is connected to the i i-th ant colony. Print a blank line between datasets.

Sample Input

5 
-42 58 
44 86 
7 28 
99 34 
-13 -59 
-47 -44 
86 74 
68 -75 
-68 60 
99 -60

Sample Output

4 
2 
1 
5 
3


#include<cstring>
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>

using namespace std;

const int maxn=555;
#define INF 0x3f3f3f3f
double w[maxn][maxn],x[maxn],y[maxn],slack[maxn];
int prev_x[maxn],prev_y[maxn],matchy[maxn],par[maxn];
int n;
int ax[maxn],ay[maxn],bx[maxn],by[maxn];
int mx[maxn];

void update(int v)
{
    matchy[v]=prev_y[v];
    if(prev_x[matchy[v]]!=-2) update(prev_x[matchy[v]]);
}

bool find(int v)
{
    for(int i=1;i<=n;i++)
    {
        if(prev_y[i]==-1)
        {
            if(slack[i]>x[v]+y[i]-w[v][i])
            {
                slack[i]=x[v]+y[i]-w[v][i];
                par[i]=v;
            }
            if(x[v]+y[i]==w[v][i])
            {
                prev_y[i]=v;
                if(matchy[i]==-1)
                {
                    update(i);
                    return true;
                }
                if(prev_x[matchy[i]]!=-1) continue;
                prev_x[matchy[i]]=i;
                if(find(matchy[i])) return true;
            }
        }
    }
    return false;
}

double km()
{
    double m;
    for(int i=1;i<=n;i++)
    {
        matchy[i]=-1;
        y[i]=0;
    }
    for(int i=1;i<=n;i++)
    {
        x[i]=0;
        for(int j=0;j<n;j++) x[i]=max(x[i],w[i][j]);
    }
    bool flag;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            prev_x[j]=prev_y[j]=-1;
            slack[j]=INF;
        }
        prev_x[i]=-2;
        if(find(i)) continue;
        flag=false;
        while(!flag)
        {
            m=INF;
            for(int j=1;j<=n;j++)
                if(prev_y[j]==-1)
                    m=min(m,slack[j]);
            for(int j=1;j<=n;j++)
            {
                if(prev_x[j]!=-1)
                    x[j]-=m;
                if(prev_y[j]!=-1)
                    y[j]+=m;
                else
                    slack[j]-=m;
            }
            for(int j=1;j<=n;j++)
                if(prev_y[j]==-1 && !slack[j])
                {
                    prev_y[j]=par[j];
                    if(matchy[j]==-1)
                    {
                        update(j);
                        flag=true;
                        break;
                    }
                    prev_x[matchy[j]]=j;
                    if(find(matchy[j]))
                    {
                        flag=true;
                        break;
                    }
                }
        }
    }
    double ans=0;
    for(int i=1;i<=n;i++) ans+=w[matchy[i]][i];
    return ans;
}

double dist(int i,int j)
{
    return sqrt((ax[i]-bx[j])*(ax[i]-bx[j])+abs(ay[i]-by[j])*abs(ay[i]-by[j]));
}


int main()
{
    int f=0;
    while(~scanf("%d",&n))
    {
        if(f) printf("\n");
        f=1;
        for(int i=1;i<=n;i++) scanf("%d%d",&ax[i],&ay[i]);
        for(int i=1;i<=n;i++) scanf("%d%d",&bx[i],&by[i]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                w[i][j]=-dist(i,j);
        n;
        km();
        for(int i=1;i<=n;i++)
            mx[matchy[i]]=i;
        for(int i=1;i<=n;i++)
            printf("%d\n",mx[i]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值