题意:给出N个白点和N个黑点,要求用N条不相交的线段把它们连接起来,其中每条线段恰好连接一个白点和一个黑点,每个点恰好连接到一条线段。

分析:因为有结点黑白两色,我们不难想到构造一个二分图,其中每个白点对应一个X结点,每个黑点对应一个Y结点,每个黑点和每个白点相连,权值等于二者的欧几里德距离。建模后最佳完美匹配就是问题的解。为什么呢?假设在最佳完美匹配中有两条线段a1-b1与a2-b2相交,那么dist(a1,b1)+dist(a2,b2)一定大于dist(a1,b2)+dist(a2,b1),因此如果把这两条改成a1-b2和a2-b1后总长度会变少,与最佳二字矛盾。

注意:KM算法是求权值和最大的,故需要将距离边成负数即可。并且输入坐标值好像是浮点的。

参考自:http://www.cnblogs.com/arbitrary/archive/2013/02/27/2936008.html

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define Del(x,y) memset(x,y,sizeof(x))
#define N 105
#define INF 999999999
struct Point
{
double x,y;
} point[N*]; double dis(Point a,Point b)
{
return sqrt((double)((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
} double lx[N],ly[N]; //顶点标号
int link[N];       //存放与T点集连结的S点集里的点
int S[N],T[N]; //visit,是否属于相等子图
double w[N][N];
int n; bool match(int i) //匈牙利
{
S[i]=true;
for(int j=;j<=n;j++)
{
if(abs(lx[i]+ly[j]-w[i][j])<10e-&&!T[j])
{
T[j]=true;
if(link[j]==||match(link[j]))
{
link[j]=i;
return true;
}
}
}
return false;
} void update() //更新顶点标号
{
double a=INF;
for(int i=;i<=n;i++)
if(S[i])
for(int j=;j<=n;j++)
if(!T[j])
a=min(a,lx[i]+ly[j]-w[i][j]);
for(int i=;i<=n;i++)
{
if(S[i]) lx[i]-=a; //S集里的点-a
if(T[i]) ly[i]+=a; //T集里的点+a
}              //其余所有点不变
} void KM()
{
for(int i=; i<=n; i++)
{
link[i]=lx[i]=ly[i]=;
for(int j=; j<=n; j++)
lx[i]=max(lx[i],w[i][j]);
}
for(int i=; i<=n; i++)
for(;;)
{
Del(S,);
Del(T,);
if(match(i))break;
else update();
}
} int ans[N]; int main()
{
scanf("%d",&n);
for(int i=; i<=n*; i++)
scanf("%lf%lf",&point[i].x,&point[i].y);
for(int i=; i<=n; i++)
for(int j=; j<=n; j++)
w[i][j]=-dis(point[i],point[j+n]);
KM();
for(int i=;i<=n;i++)
ans[link[i]]=i;
for(int i=;i<=n;i++)
printf("%d\n",ans[i]);
return ;
}

POJ_3565_Ants的更多相关文章

随机推荐

  1. Tcl学习之--文件操作

    Tcl中文件名称操作遵循Unix/Linux的命名规范. x/y/z表示x文件夹下的y 子文件夹及y以下的子文件夹z. ~admin/email则表示admin用户的email目录. l  file ...

  2. hdu oj 1285 确定比赛名次

    hdu oj 1285 确定比赛名次 题目: 确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  3. EXCEL单元格的获取——多例模式

    因为Excel的单元格的行列与单元格是一一相应的,行与列组成的是一对联合主键.给定一个单元格行列或者给定一个单元格名称.须要找到相应的单元格:这样就形成了一种映射关系.须要使用单例模式的变式--多例模 ...

  4. .net Core使用Orcle官方驱动连接数据库 C#参考教程 http://www.csref.cn

    .net Core使用Orcle官方驱动连接数据库   最近在研究.net Core,因为公司的项目用到的都是Oracle数据库,所以简单试一下.net Core怎样连接Oracle. Oracle官 ...

  5. 【智能家居篇】wifi网络结构(下)

    转载请注明出处:http://blog.csdn.net/Righthek 谢谢. 因为WIFI网络具有移动性,同一时候WIFI以无线电波作为传输媒介,这样的媒介本质上是开放的,且easy被拦截,不论 ...

  6. POJ1469 COURSES 【二分图最大匹配&#183;HK算法】

    COURSES Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17777   Accepted: 7007 Descript ...

  7. Python爬虫开发【第1篇】【urllib2】

    1.urlopen # urllib2_urlopen.py # 导入urllib2 库 import urllib2 # 向指定的url发送请求,并返回服务器响应的类文件对象,urlopen中有da ...

  8. shell如何查看单个或多个文件的行数或总行数

    shell如何查看单个或多个文件的行数或总行数_百度经验 https://jingyan.baidu.com/article/cbf0e500b8470f2eab28937d.html 单个文件   ...

  9. 学习 Shell —— 认识 shell

    0. 认识 shell shell 是一个命令行解释器(interpreter),它会输出一个提示符,等待输入一个命令,然后执行该命令.如果该命令行的第一个单词不是一个内置的 shell 命令,那么 ...

  10. python-----自动解压并删除zip文件

    如何自动解压并删除zip? 如何解压  →  使用内置模块来实现(shutil.unpack_archive) 如何删除zip  →  使用内置模块os来实现(os.remove) 如何监测zip的出 ...