随着社会的不断发展,人与人之间的感情越来越功利化。最近,爱神丘比特发现,爱情也已不再是完全纯洁的了。这使得丘比特很是苦恼,他越来越难找到合适的男女,并向他们射去丘比特之箭。于是丘比特千里迢迢远赴中国,找到了掌管东方人爱情的神——月下老人,向他求教。月下老人告诉丘比特,纯洁的爱情并不是不存在,而是他没有找到。在东方,人们讲究的是缘分。月下老人只要做一男一女两个泥人,在他们之间连上一条红线,那么它们所代表的人就会相爱——无论他们身处何地。而丘比特的爱情之箭只能射中两个距离相当近的人,选择的范围自然就小了很多,不能找到真正的有缘人。丘比特听了月下老人的解释,茅塞顿开,回去之后用了人间的最新科技改造了自己的弓箭,使得丘比特之箭的射程大大增加。这样,射中有缘人的机会也增加了不少。情人节(Valentine's day)的午夜零时,丘比特开始了自己的工作。他选择了一组数目相等的男女,感应到他们互相之间的缘分大小,并依此射出了神箭,使他们产生爱意。他希望能选择最好的方法,使被他选择的每一个人被射中一次,且每一对被射中的人之间的缘分的和最大。当然,无论丘比特怎么改造自己的弓箭,总还是存在缺陷的。首先,弓箭的射程尽管增大了,但毕竟还是有限的,不能像月下老人那样,做到“千里姻缘一线牵”。其次,无论怎么改造,箭的轨迹终归只能是一条直线,也就是说,如果两个人之间的连线段上有别人,那么莫不可向他们射出丘比特之箭,否则,按月下老人的话,就是“乱点鸳鸯谱”了。作为一个凡人,你的任务是运用先进的计算机为丘比特找到最佳的方案。输入文件格式:输入文件第一行为正整数k,表示丘比特之箭的射程,第二行为正整数n(n<30),随后有2n行,表示丘比特选中的人的信息,其中前n行为男子,后n行为女子。每个人的信息由两部分组成:他的姓名和他的位置。姓名是长度小于20且仅包含字母的字符串,忽略大小写的区别,位置是由一对整数表示的坐标,它们之间用空格分隔。格式为Name x y。输入文件剩下的部分描述了这些人的缘分。每一行的格式为Name1 Name2 p。Name1和Name2为有缘人的姓名,p是他们之间的缘分值(p为小于等于255的正整数)。以一个End作为文件结束标志。每两个人之间的缘分至多只被描述一次。如果没有被描述,则说明他们缘分值为1。输出文件格式:输出文件仅一个正整数,表示每一对被射中的人之间的缘分的总和。这个和应当是最大的。输入样例(cupid.in):
2
3
0 0 Adam
1 1 Jack
0 2 George
1 0 Victoria
0 1 Susan
1 2 Cathy
Adam Cathy 100
Susan George 20
George Cathy 40
Jack Susan 5
Cathy Jack 30
Victoria Jack 20
Adam Victoria 15
End输出样例(cupid.out):
65

這是一道最佳匹配問題,用KM算法可以解決。

首先建圖,若兩點距離大於d或連線中有第三者,則權值賦為負無窮,保證這條邊永遠不能被取到。

具體細節見程序注釋。

Accode:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <bitset>
#include <map>
using namespace std;const char fi[] = "cupid.in";
const char fo[] = "cupid.out";
const int maxN = 50;
const int MAX = 0x3fffff00;
const int MIN = -MAX;map <string, int> _boy, _girl;
int w[maxN][maxN];
int lx[maxN], ly[maxN];
int bx[maxN], by[maxN];
int gx[maxN], gy[maxN];
int Link[maxN];
bitset <maxN> boy, girl;
int n, d, t;
string str, str1, str2;void init_file(){freopen(fi, "r", stdin);freopen(fo, "w", stdout);std::ios::sync_with_stdio(false);}inline bool line(int x1, int y1,int x2, int y2, int x3, int y3){int _x1 = x2 - x1;int _y1 = y2 - y1;int _x2 = x2 - x3;int _y2 = y2 - y3;if (_x1 * _y2 != _y1 * _x2)return false;if (_x1 * _x2 + _y1 * _y2 < 0)return true;return false;} //判斷(x2, y2)是否在(x1, y1)與(x3, y3)的連線上。inline int sqr(int x) {return x * x; }inline void ltu(string &str){string::iterator iter;for (iter = str.begin();iter != str.end(); ++iter)if ((*iter) >= 'a' && (*iter) <= 'z')(*iter) -= 'a' - 'A';} //小寫轉大寫。void readdata(){cin >> d >> n;for (int i = 1; i < n + 1; ++i){cin >> bx[i] >> by[i] >> str;ltu(str);_boy.insert(make_pair(str, i));}for (int j = 1; j < n + 1; ++j){cin >> gx[j] >> gy[j] >> str;ltu(str);_girl.insert(make_pair(str, j));}while (1){cin >> str1 >> str2 >> t;ltu(str1); ltu(str2);//由於題目中忽略大小寫,所以將小寫全部轉化為大寫。if (str1 == "END") break;if (_boy.find(str1) == _boy.end())swap(str1, str2);w[_boy[str1]][_girl[str2]] = t;}}void Modify(){for (int i = 1; i < n + 1; ++i)lx[i] = MIN;//頂標初始為負無窮。for (int i = 1; i < n + 1; ++i)for (int j = 1; j < n + 1; ++j){if (!w[i][j]) w[i][j] = 1;if (sqr(bx[i] - gx[j])+ sqr(by[i] - gy[j]) > sqr(d)){w[i][j] = MIN; continue; }if (w[i][j] > 0){for (int i1 = 1; i1 < n + 1; ++i1)if (i != i1)if (line(bx[i], by[i], bx[i1],by[i1], gx[j], gy[j])){w[i][j] = MIN; break; }} else continue;//枚舉查看連線中間是否有其他男生。if (w[i][j] > 0){for (int j1 = 1; j1 < n + 1; ++j1)if (j != j1)if (line(bx[i], by[i], gx[j1],gy[j1], gx[j], gy[j])){w[i][j] = MIN; break; }} else continue;//枚舉查看連線中間是否有其他女生。lx[i] = max(lx[i], w[i][j]);//更新頂標。}}bool Find(int u){boy.set(u);for (int v = 1; v < n + 1; ++v)if (lx[u] + ly[v] == w[u][v]&& !girl.test(v)){girl.set(v);if (!Link[v] || Find(Link[v])){Link[v] = u; return true; }}return false;}void work(){for (int k = 1; k < n + 1; ++k)while (1){boy.reset();girl.reset();if (Find(k)) break;int Min = MAX;for (int i = 1; i < n + 1; ++i)if (boy.test(i))for (int j = 1; j < n + 1; ++j)if (!girl.test(j))Min = min(Min, lx[i]+ ly[j] - w[i][j]);for (int i = 1; i < n + 1; ++i){if (boy.test(i)) lx[i] -= Min;if (girl.test(i)) ly[i] += Min;}}int ans = 0;for (int j = 1; j < n + 1; ++j)ans += w[Link[j]][j];printf("%d", ans);}int main()
{init_file();readdata();Modify();work();exit(0);
}

第二次做:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
using namespace std;const char fi[] = "cupid.in";
const char fo[] = "cupid.out";
const int maxN = 40;
const int MAX = 0x3f3f3f3f;
const int MIN = ~MAX;struct vec
{int x, y;vec() {}vec(int x, int y): x(x), y(y) {}vec operator-(const vec &b) const{return vec(x - b.x, y - b.y);}int operator+(const vec &b) const{return x * b.x + y * b.y;}int operator*(const vec &b) const{return x * b.y - y * b.x;}int norm() const {return x * x + y * y;}bool btwn(const vec &A, const vec &B) const{vec OA = vec(A.x - x, A.y - y),OB = vec(B.x - x, B.y - y);return !(OA * OB) && OA + OB < 0;}
};
map <string, int> _boy, _girl;
vec boy[maxN], girl[maxN];
bool b[maxN], g[maxN];
int lx[maxN], ly[maxN], Link[maxN];
int mp[maxN][maxN], n, K;void init_file()
{freopen(fi, "r", stdin);freopen(fo, "w", stdout);return;
}void readdata()
{cin >> K >> n;for (int i = 0; i < n; ++i){int x, y; string str;cin >> x >> y >> str;boy[i] = vec(x, y);transform(str.begin(), str.end(),str.begin(), ::tolower);//将一个string类型转换为小写。_boy[str] = i;}for (int i = 0; i < n; ++i){int x, y; string str;cin >> x >> y >> str;girl[i] = vec(x, y);transform(str.begin(), str.end(),str.begin(), ::tolower);_girl[str] = i;Link[i] = -1;}int w; string s1, s2;while (cin >> s1 >> s2 >> w){transform(s1.begin(), s1.end(),s1.begin(), ::tolower);transform(s2.begin(), s2.end(),s2.begin(), ::tolower);if (_boy.find(s1) == _boy.end())swap(s1, s2);mp[_boy[s1]][_girl[s2]] = w;}return;
}void modify()
{for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j){if (!mp[i][j]) mp[i][j] = 1;if ((boy[i] - girl[j]).norm() > K * K){mp[i][j] = MIN; continue;}if (mp[i][j] > 0)for (int i1 = 0; i1 < n; ++i1)if (i1 != i && boy[i1].btwn(boy[i], girl[j])){mp[i][j] = MIN; break;}if (mp[i][j] > 0)for (int j1 = 0; j1 < n; ++j1)if (j1 != j && girl[j1].btwn(boy[i], girl[j])){mp[i][j] = MIN; break;}lx[i] = max(lx[i], mp[i][j]);} //当不能连边时一定要把权值设为负无穷。return;
}bool Find(int i)
{b[i] = 1;for (int j = 0; j < n; ++j)if (lx[i] + ly[j] == mp[i][j] && !g[j]){g[j] = 1;if (Link[j] == -1 || Find(Link[j])){Link[j] = i;return 1;}}return 0;
}void work()
{for (int k = 0; k < n; ++k)while (1){memset(b, 0, sizeof b);memset(g, 0, sizeof g);if (Find(k)) break;int Min = MAX;for (int i = 0; i < n; ++i) if (b[i])for (int j = 0; j < n; ++j) if (!g[j])Min = min(Min, lx[i] + ly[j] - mp[i][j]);for (int i = 0; i < n; ++i){if (b[i]) lx[i] -= Min;if (g[i]) ly[i] += Min;}}int ans = 0;for (int j = 0; j < n; ++j)ans += mp[Link[j]][j];printf("%d\n", ans);return;
}int main()
{init_file();readdata();modify();work();return 0;
}

★☆【二分圖最佳匹配】丘比特的煩惱相关推荐

  1. 二分图带权匹配、最佳匹配与KM算法

    ---------------------以上转自ByVoid神牛博客,并有所省略.   [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值 ...

  2. 如何实现示波器探头的最佳匹配?

    摘要:探头是观测信号的第一个环节,主要作用是承载信号传输的链路,将待测信号完整.可靠的传输至示波器,进行测量分析.可是你知道如何实现探头的最佳匹配吗? 1. 探头分类 探头通常按测量对象进行分类,分类 ...

  3. 洛谷 P2756 飞行员配对方案问题 (二分图/网络流,最佳匹配方案)

    P2756 飞行员配对方案问题 题目背景 第二次世界大战时期.. 题目描述 英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其 ...

  4. POJ 2195 【二分图最佳匹配】.cpp

    题意: 有 n 个房子和 n 个人 每个人走一个单元你就要付 1$ 有什么办法可以让把所有人都分派到房子里 而花费最少 输入: 给出n m 表示该矩阵由n 行 m 列组成 然后给出一个n*m的图 . ...

  5. 17.立体匹配——介绍,匹配,寻找最佳匹配 Matlab实战_1

    目录 介绍 匹配 寻找最佳匹配 实战 介绍 欢迎回到计算机视觉.今天我们要讲的是立体视觉匹配(stereo correspondence).到目前为止,我们已经定义了对极几何(epipolar geo ...

  6. 运动估计和最佳匹配块搜索算法

    图像与视频的区别:图像是静态的,只有一帧:视频是动态的,是由多帧连续图像组成的运动图像序列,视频具有的时间冗余是图像所没有的. 时间冗余:视频中时间上相邻图像之间的相似性,重复性称为时间冗余 帧间预测 ...

  7. POJ365Ants_二分图最佳匹配

    https://blog.csdn.net/lianai911/article/details/44835659 题意: 在坐标系中有N只蚂蚁,N棵苹果树,给你蚂蚁和苹果树的坐标.让每只蚂蚁去一棵苹果 ...

  8. HDU - 奔小康赚大钱(二分图最佳匹配+KM)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 Time Limit: 1000/1000 MS (Java/Others) Memory Li ...

  9. 运动员最佳匹配问题(详解)

    一.问题描述 羽毛球队有男女运动员各n人.给定2个n×n矩阵P和Q. P[i][j]是男运动员i的女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配对的女运动员竞赛 ...

最新文章

  1. 同一个PC只能运行一个应用实例(考虑多个用户会话情况)
  2. 跟我一起屏蔽百度搜索页面右侧的内容
  3. 2017.10.16 模拟赛
  4. 【UVA12304】2D Geometry 110 in 1!(外接圆/内切圆/切点等圆相关问题的模版题)
  5. Latex找不到字体:Package fontspec: The font “simsun“ cannot be found
  6. 同构数的算法——C语言
  7. 将图片转化成RGB格式
  8. 模糊逻辑基本原理与编程
  9. MSSQL 2000 823错误原因分析及数据恢复方案
  10. oracle11g数据备份,oracle11g备份还原
  11. 章文嵩坐镇淘宝双11流量作战室
  12. 《正确写作美国大学生数学竞赛论文》摘录笔记
  13. element-ui el-table 表格疯狂抖动
  14. 《富爸爸穷爸爸》读书笔记
  15. Lodop打印较大的超出纸张的图片
  16. iOS 极光推送没有声音怎么办?
  17. 【iOS】AFNetworking
  18. gocron mysql_[日常] gocron源码阅读-使用go mod管理依赖源码启动gocron
  19. java swing(GUI) MySQL实现的学生选课签到考勤系统源码开发教程
  20. mysql是什么数据库

热门文章

  1. 安装ps显示检测到计算机,修复:win10下Photoshop遇到显示驱动程序问题
  2. 瑞萨R78族Flash读写操作详细探讨
  3. 腾讯Oceanus实时计算平台架构设计---学习总结
  4. 海康、华为、中兴、联影...找工作记录
  5. python经典程序练习题-Python练习题(基础知识练习题(一))
  6. 基于图像的虚拟试衣:Image Based Virtual Try-On Network from Unpaired Data
  7. 可以放置Google Adsense广告的博客汇总
  8. 云呐数据备份|什么是离线磁带设备
  9. windows常用 API函数
  10. 读书笔记——数学之美