Description

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.

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

The first line of the input file contains a single integer number n (1 ≤ n ≤ 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 (−10 000 ≤ xy ≤ 10 000) 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

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-th ant colony.

题目大意:n个点A和n个点B,每一点A到一点B连一条线,要求n条线互不相交,求一种方案。

思路:可以证明,在费用最小的完美匹配下,所有连线没有相交。这里不证。

PS:WA了几遍才发现平方和最小,和不一定最小……

PS2:跑的是ZKW费用流,我是一个懒人没有改邻接矩阵……

代码(1797MS)(ZKW费用流):

 //忘删调试语句了……
#include <cstdio>
#include <iostream>
#include <queue>
#include <cmath>
#include <cstring>
using namespace std; const int MAXV = ;
const int MAXE = MAXV * MAXV;
const double INF = 1e100;
const double EPS = 1e-; inline int sgn(double x) {
return (x > EPS) - (x < -EPS);
} struct ZWK_FLOW {
int head[MAXV];
double dis[MAXV];
int next[MAXE], to[MAXE], cap[MAXE];
double cost[MAXE];
int st, ed, ecnt, n; void init() {
memset(head, , sizeof(head));
ecnt = ;
} void add_edge(int u, int v, int c, double w) {
to[ecnt] = v; cap[ecnt] = c; cost[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; cap[ecnt] = ; cost[ecnt] = -w; next[ecnt] = head[v]; head[v] = ecnt++;
//printf("%d %d %f\n", u, v - 5, w);
} void SPFA() {
for(int i = ; i <= n; ++i) dis[i] = INF;
priority_queue<pair<double, int> > que;
dis[st] = ;
que.push(make_pair(, st));
while(!que.empty()) {
int u = que.top().second; double d = -que.top().first; que.pop();
if(sgn(d - dis[u]) != ) continue;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(cap[p] && sgn(dis[v] - d - cost[p]) > ) {
dis[v] = d + cost[p];
que.push(make_pair(-dis[v], v));
}
}
}
for(int i = ; i <= n; ++i) dis[i] = dis[ed] - dis[i];
} double minCost;
int maxFlow;
bool use[MAXV]; int add_flow(int u, int aug) {
if(u == ed) {
maxFlow += aug;
minCost += dis[st] * aug;
return aug;
}
use[u] = true;
int now = aug;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(cap[p] && !use[v] && sgn(dis[u] - dis[v] - cost[p]) == ) {
int t = add_flow(v, min(now, cap[p]));
cap[p] -= t;
cap[p ^ ] += t;
now -= t;
if(!now) break;
}
}
return aug - now;
} bool modify_label() {
double d = INF;
for(int u = ; u <= n; ++u) if(use[u])
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(cap[p] && !use[v]) d = min(d, dis[v] + cost[p] - dis[u]);
}
if(sgn(INF - d) == ) return false;
for(int i = ; i <= n; ++i) if(use[i]) dis[i] += d;
return true;
} double min_cost_flow(int ss, int tt, int nn) {
st = ss, ed = tt, n = nn;
minCost = maxFlow = ;
SPFA();
while(true) {
while(true) {
for(int i = ; i <= n; ++i) use[i] = ;
if(!add_flow(st, 0x7fffffff)) break;
}
if(!modify_label()) break;
}
return minCost;
} void output(int n) {
for(int i = ; i <= n; ++i) {
for(int p = head[i]; p; p = next[p]) {
int &v = to[p];
if(!cap[p]) {printf("%d\n", v - n); break;}
}
}
}
} G; struct Point {
int x, y;
Point() {}
Point(int x, int y): x(x), y(y) {}
void read() {
scanf("%d%d", &x, &y);
}
Point operator - (const Point &rhs) const {
return Point(x - rhs.x, y - rhs.y);
}
double operator * (const Point &rhs) const {
Point a(*this - rhs);
return sqrt(a.x * a.x + a.y * a.y);
}
}; Point p[MAXV];
int n; int main() {
bool flag = true;
while(scanf("%d", &n) != EOF) {
if(flag) flag = false; else puts("");
for(int i = ; i <= * n; ++i) p[i].read();
G.init();
for(int i = ; i <= n; ++i) {
for(int j = n + ; j <= * n; ++j) G.add_edge(i, j, , p[i] * p[j]);
}
int ss = * n + , tt = * n + ;
for(int i = ; i <= n; ++i) G.add_edge(ss, i, , );
for(int i = n + ; i <= n + n; ++i) G.add_edge(i, tt, , );
G.min_cost_flow(ss, tt, tt);
//printf("%d\n", x);
G.output(n);
}
}

代码(94MS)(顺便用一下KM算法):

 //囧,KM都写了顺便改一下吧
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std; const int MAXN = ;
const double INF = 1e100;
const double EPS = 1e-; inline int sgn(double x) {
return (x > EPS) - (x < -EPS);
} int n;
double mat[MAXN][MAXN], slack[MAXN], Lx[MAXN], Ly[MAXN];
int left[MAXN];
bool S[MAXN], T[MAXN]; bool dfs(int i) {
S[i] = true;
for(int j = ; j <= n; ++j) if(!T[j]) {
double t = Lx[i] + Ly[j] - mat[i][j];
if(sgn(t) == ){
T[j] = true;
if(!left[j] || dfs(left[j])){
left[j] = i;
return true;
}
}
else slack[j] = min(slack[j],t);
}
return false;
} void update() {
double a = INF;
for(int i = ; i <= n; ++i) if(!T[i])
a = min(slack[i],a);
for(int i = ; i <= n; ++i){
if(S[i]) Lx[i] -= a;
if(T[i]) Ly[i] += a; else slack[i] -= a;
}
} void KM() {
for(int i = ; i <= n; ++i) {
Lx[i] = Ly[i] = left[i] = ;
for(int j = ; j <= n; ++j) Lx[i] = max(Lx[i], mat[i][j]);
}
for(int i = ; i <= n; ++i) {
for(int j = ; j <= n; ++j) slack[j] = INF;
while(true){
for(int j = ; j <= n; ++j) S[j] = T[j] = ;
if(dfs(i)) break; else update();
}
}
//int ans = 0;
//for(int i = 1; i <=n; ++i) ans += Lx[i] + Ly[i];
//return ans;
} void output() {
for(int i = ; i <= n; ++i) printf("%d\n", left[i]);
} struct Point {
int x, y;
Point() {}
Point(int x, int y): x(x), y(y) {}
void read() {
scanf("%d%d", &x, &y);
}
Point operator - (const Point &rhs) const {
return Point(x - rhs.x, y - rhs.y);
}
double operator * (const Point &rhs) const {
Point a(*this - rhs);
return sqrt(a.x * a.x + a.y * a.y);
}
}; Point p1[MAXN], p2[MAXN]; int main() {
bool flag = true;
while(scanf("%d", &n) != EOF) {
if(flag) flag = false; else puts("");
for(int i = ; i <= n; ++i) p1[i].read();
for(int i = ; i <= n; ++i) p2[i].read();
for(int i = ; i <= n; ++i) {
for(int j = ; j <= n; ++j) mat[j][i] = -(p1[i] * p2[j]);
}
KM();
output();
}
}

POJ 3565 Ants(最佳完美匹配)的更多相关文章

  1. UVaLive 4043 Ants (最佳完美匹配)

    题意:给定 n 个只蚂蚁和 n 棵树的坐标,问怎么匹配使得每个蚂蚁到树的连线不相交. 析:可以把蚂蚁和树分别看成是两类,那么就是一个完全匹配就好,但是要他们的连线不相交,那么就得考虑,最佳完美匹配是可 ...

  2. POJ 3565 Ants (最小权匹配)

    题意 给出一些蚂蚁的点,给出一些树的点,两两对应,使他们的连线不相交,输出一种方案. 思路 一开始没想到怎么用最小权匹配--后来发现是因为最小权匹配的方案一定不相交(三角形两边之和大于第三边)--还是 ...

  3. Ants(二分图最佳完美匹配)

    Ants Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 6904   Accepted: 2164   Special Ju ...

  4. UVa1349 Optimal Bus Route Design(二分图最佳完美匹配)

    UVA - 1349 Optimal Bus Route Design Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & ...

  5. UVa 11383 少林决胜(二分图最佳完美匹配)

    https://vjudge.net/problem/UVA-11383 题意: 给定一个N×N矩阵,每个格子里都有一个正整数W(i,j).你的任务是给每行确定一个整数row(i),每列也确定一个整数 ...

  6. 【LA4043 训练指南】蚂蚁 【二分图最佳完美匹配,费用流】

    题意 给出n个白点和n个黑点的坐标,要求用n条不相交的线段把他们连接起来,其中每条线段恰好连接一个白点和一个黑点,每个点恰好连接一条线段. 分析 结点分黑白,很容易想到二分图.其中每个白点对应一个X结 ...

  7. UVA - 1045 The Great Wall Game(二分图最佳完美匹配)

    题目大意:给出棋盘上的N个点的位置.如今问将这些点排成一行或者一列.或者对角线的最小移动步数(每一个点都仅仅能上下左右移动.一次移动一个) 解题思路:暴力+二分图最佳完美匹配 #include < ...

  8. Uva1349Optimal Bus Route Design(二分图最佳完美匹配)(最小值)

    题意: 给定n个点的有向图问,问能不能找到若干个环,让所有点都在环中,且让权值最小,KM算法求最佳完美匹配,只不过是最小值,所以把边权变成负值,输出时将ans取负即可 这道题是在VJ上交的 #incl ...

  9. UVALive 4043 转化最佳完美匹配

    首先黑点和白点是组成一个二分图这毫无疑问 关键是题目中要求的所有黑白配的线不能交叉...一开始我也没想到这个怎么转化为二分图里面的算法. 后来看书才知道,如果两两交叉,则可以把两根线当四边形的对角线, ...

随机推荐

  1. java的引用总结

    四种引用:强弱软虚 强引用:使用强引用,在内存不足的时候垃圾处理器也不会回收他,哪怕导致程序崩溃 例如: A a=new A() 软引用:内存不足的时候会被回收(软引用可以和一个引用队列(Refere ...

  2. 6.Spring Cloud初相识-------Zool路由

    前言: 在生产环境中,我们不可能将每个服务的真实信息暴漏出去,因为这样太不安全. 我们会选择使用路由代理真实的服务信息,由它负责转发给真实的服务. 新建一个Zool: 1.添加依赖 <?xml ...

  3. CentOS 7安装Oracle (CentOS Linux release 7.5.1804)

    从安装操作系统到完成oracle安装 1.安装centos7 下载CentOS7 iso安装包,配置虚拟机,由于只进行oracle安装练习,随便配置20G空间.选择安装文件. 开机,开始安装系统: 直 ...

  4. mysql if...else 的使用

    select case when tca.id = '3' then 'vw' else epc_code end as epccode,tfp.product_id, tfp.vender, tfp ...

  5. rest_framework --- viewsets

    viewsets :from rest_framework import viewsets #导入方式 ViewSetMixin(object): 这个类,大致作用就是重写了as_view()方法,假 ...

  6. C++练习--创建Boat类和Car类(含友元)

    /* 定义Boat与Car两个类,二者都有weight属性, 定义二者的一个友元函数totalWeight()为外部函数, 计算二者的重量和. */ #include<iostream> ...

  7. 关于ECharts内存泄漏问题

    最近使用websocket加ECharts做了一个实时监控的功能,发现了一个比较严重的问题,就是浏览器运行一段时间就会非常卡,之前在ECharts官网运行官方实例“动态数据 + 时间坐标轴”时,也遇到 ...

  8. 微信小程序中无刷新修改

    1.点击事件无刷新修改 原理:onload事件中是把这个分类和品牌的列表全部拿出来,拼接成数组的格式,在小程序中遍历的时候就要把小标(index)给绑定到左侧的品牌上,然后js中获取index的值,就 ...

  9. 接口API封装中常见的HTTP状态码

    在进行后端接口API封装的过程中,需要考虑各种错误信息的输出.一般情况下,根据相应问题输出适合的HTTP状态码,可以方便前端快速定位错误,减少沟通成本. HTTP状态码有很多,每个都有对应的含义,下面 ...

  10. 前端学习webpack

    ### 模块化- 为了保证代码充分解耦,一个大的项目拆分成互相依赖的一个一个的小的模块,最后再通过简单的方式合并在一起- 每一个js文件都可以看成一个单独的模块在node这边(服务器端),提出Comm ...