最近做了一下hackerrank的20/20的比赛。平时都只能过2题,这周顺利地通过了四道题目竟然。当妄图冲击衬衫的时候,发现剩下三个题一点招数都没有,之后就跑去看了一下node.js了。。。

这次比赛的第四个题目是用cpp敲的,之前都是偷懒用python。

题目链接

Bike Racers

【题意描述】

在城市里有n个骑车的人,有m辆自行车,人可以同时沿着任意方向行走,每单位时间移动单位距离。要求出前k个到达自行车的人所花费的最小时间。人和自行车都用整数坐标表示。

1 <= N <= 250
1 <= M <= 250
1 <= K <= min(N,M)
0 <= xi,yi <= 107

【思路】

这一个题目,拿到之后没什么想法。然后感觉应该像是二分图的匹配问题。然后就去恶补了二分图,刷了三四道题目。第二天晚上回来,发现确实是二分图……那么大意就是求出这个图的一个子图,这个子图的二分图匹配数为k并且匹配的边中最大值最小。

那么这道题可以用类似克鲁斯卡尔最小生成树的问题来解决。将边从小到大进行排序,依次添加到图中。每次添加检测匹配数,当匹配数为k的时候,最后添加的那条边就是所求解。匹配当然是采用匈牙利算法进行。

算法确定,之后就是数据结构的问题:

如何保存图是本题的关键。

假设边以经按照权值排序完成。加边只修要O(1)的时间。

题目的总体复杂度为V*匈牙利算法的复杂度(V为边数)

匈牙利算法的复杂度为DFS的复杂度V*E(边数*点数)

通常的题目中,使用邻接矩阵来保存图,匈牙利算法就退化成为了E*E*E(V=E*E),于是总体复杂度就变成了E^5。必须会TLE。

世界就是如此美好,这个时候如果用边表来保存整个图,那么每次匈牙利算法的复杂度仍旧是V*E,总体复杂度就变为了(E*1+E*2+……+E*E*E)=1/2*(E^3)*(E+1)大约为E^4。看上去好很多了。

排序的优化:

为了让算法看上去更快一点,我又对排序这个地方产生了想法,如果排序的话,排序的复杂度为:

V*logV = E*E*log(E*E) = 2E*ElogE。在最坏的情况下,加入了最后一条边才能出结果,这个时候复杂度是不会有改善的。这里考虑平均情况,也就是说不需要每次都用到所有的边,这个时候使用小顶堆可以胜任!

以下是拙劣的代码。窃喜一下,还是觉得有长进的…

   1: #include <iostream>

   2: #include <cstring>

   3: #include <algorithm>

   4: #include <queue>

   5:  

   6: using namespace std;

   7:  

   8: struct Point {

   9:     long long x,y;

  10:     Point( long long _x, long long _y ) {

  11:         x = _x;

  12:         y = _y;

  13:     }

  14:     Point() {}

  15:     long long dis( Point p ) {

  16:         long long lx = x - p.x;

  17:         long long ly = y - p.y;

  18:         lx *= lx;

  19:         ly *= ly;

  20:         return lx+ly;

  21:     }

  22: };

  23:  

  24: struct Edge {

  25:     int y,next;

  26:     long long l;

  27:     Edge ( int _y, long long  _l, int _next ) {

  28:         y = _y;

  29:         next = _next;

  30:         l = _l;

  31:     }

  32:     Edge () {}

  33: };

  34:  

  35: struct E{

  36:     int x,y;

  37:     long long l;

  38:     E( int _x, int _y, long long _l ) {

  39:         x = _x;

  40:         y = _y;

  41:         l = _l;

  42:     }

  43:     E(){}

  44:     bool operator<( const E &e ) const {

  45:         return l > e.l;

  46:     }

  47: };

  48:  

  49: const int MAXSIZE = 255;

  50: const int NC = MAXSIZE*2;

  51:  

  52: priority_queue<E> Q;

  53:  

  54: int head[NC];

  55: Edge e[MAXSIZE*MAXSIZE];

  56: Point p[MAXSIZE];

  57: int visited[NC];

  58: int mark[NC];

  59:  

  60:  

  61: int e_len;

  62: int n,m,k;

  63: long long last;

  64:  

  65: void add( E ex ) {

  66:     e[e_len] = Edge(ex.y,ex.l,head[ex.x]);

  67:     head[ex.x] = e_len++;

  68: }

  69:  

  70: void input() {

  71:     while ( !Q.empty() ) {

  72:         Q.pop();

  73:     }

  74:     memset(e,-1,sizeof(e));

  75:     memset(head,-1,sizeof(head));

  76:     memset(p,0,sizeof(p));

  77:     e_len = 0;

  78:     cin>>n>>m>>k;

  79:     for ( int i = 0; i < n; i++ ) {

  80:         long long x,y;

  81:         cin>>x>>y;

  82:         p[i] = Point(x,y);

  83:     }

  84:     for ( int i = 0; i < m; i++ ) {

  85:         long long x,y;

  86:         cin>>x>>y;

  87:         Point t(x,y);

  88:         for ( int j = 0; j < n; j++ ) {

  89:             Q.push(E(j,MAXSIZE+i,t.dis(p[j])));

  90:         }

  91:     }

  92: }

  93:  

  94: int DFS( int x ) {

  95:     for ( int i = head[x]; i != -1; i = e[i].next ) {

  96:         int y = e[i].y;

  97:         if ( !visited[y] ) {

  98:             visited[y] = 1;

  99:             if ( ( -1 == mark[y] ) || ( DFS(mark[y]) ) ) {

 100:                 mark[y] = x;

 101:                 return 1;

 102:             }

 103:         }

 104:     }

 105:    return 0;

 106: }

 107:  

 108: bool test() {

 109:     memset(mark,-1,sizeof(mark));

 110:     int result = 0;

 111:     for ( int i = 0; i < n; i++ ) {

 112:         memset(visited,0,sizeof(visited));

 113:         result += DFS(i);

 114:     }

 115:     if ( result == k ) {

 116:         return true;

 117:     } else {

 118:         return false;

 119:     }

 120: }

 121:  

 122: void solve () {

 123:     for ( int i = 0; i < k; i++ ) {

 124:         E ex = Q.top();

 125:         Q.pop();

 126:         add(ex);

 127:         last = ex.l;

 128:     }

 129:     while ( !test() ) {

 130:         E ex = Q.top();

 131:         Q.pop();

 132:         add(ex);

 133:         last = ex.l;

 134:     }

 135:     cout<<last<<endl;

 136: }

 137:  

 138: int main() {

 139:     input();

 140:     solve();

 141: }

来更新一篇blog吧的更多相关文章

  1. 如何在一小时内更新100篇文章?-Evernote Sync插件介绍

    上一篇"手把手教你制作微信小程序,开源.免费.快速搞定",已经教会你如何快速制作一个小程序,但作为资讯类小程序,内容不可少,并且还需要及时更新. 但是,如果让你复制粘贴,可能还需要 ...

  2. 一篇blog带你了解java中的锁

    前言 最近在复习锁这一块,对java中的锁进行整理,本文介绍各种锁,希望给大家带来帮助. Java的锁 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人 ...

  3. 第一篇blog

    之前不用blog,但是在杭电oj,poj上刷题,总会自己总结题型和使用什么算法,算法模板,自己在笔记本上写,耗时费力,感觉用键盘敲得总结,分享,大家相互学习提高.有时遇到不会做的,或者总是在oj上跑的 ...

  4. 我的第一篇blog

    加入博客园两年多了,学习.从事编程也两年多了,一直是在网上找资料,都没有认真写写博客. 博客园里面好多功能都还不会用,今天起我也要在博客园写自己的blog了.感觉很高大上的样纸!!

  5. 空格哥的第一篇Blog

    首先十分感谢博客园在这里给我的平台,我在这里学习到了很多东西,响应的,我也想要在这里记录下自己的心路历程!在学习的过程中,希望博客园一直陪伴我,小弟在这里不胜感激!这是小弟的第一篇博客,很多东西都不是 ...

  6. 更新几篇之前写在公众号上的文章:线性可分时SVM理论推导;关联分析做捆绑销售和推荐;分词、去停用词和画词云

    适合阅读人群:有一定的数学基础. 这几篇文章是16年写的,之前发布在个人公众号上,公众号现已弃用.回过头来再看这几篇文章,发现写的过于稚嫩,思考也不全面,这说明我又进步了,但还是作为学习笔记记在这里了 ...

  7. 我的第一篇blog—— 一起来赛马呀

      作为一名大三的学生现在开始学习acm,或许太晚.感叹时光蹉跎....我的blog将以讲解的形式的发布,以专题的形式的形式介绍一些基本的知识和经典的题目.虽然感觉自己所剩时间无多,但也希望起到前人种 ...

  8. 人生的第一篇blog

    开始写博客了,人生第一篇博客啊,要写些什么呢?想想也没有什么头绪,随便写写吧. 这学期要使用代码管理工具了,要写团队项目了.一直以来都是自己一个人在默默编程,没有过合作经历.对于代码的管理也只是一直在 ...

  9. EC2的维护更新-总结篇及有效经验分享

    2014年10月11日 号,我们对不到10%的EC2实例的完毕了重新启动.来预防不论什么与Xen安全通报(XSA-108)相关的安全风险. 日之前都有义务遵守相关问题的保密要求.直到它被向公众公布. ...

随机推荐

  1. vs2013 使用vs调试器,发现调试器显示的数据错误。查看内存,发现内存是正确的。

    有可能只是调试器的问题,程序可以正常运行的! 网上没找到此种情况解释.感觉有可能是那里堆被破坏了.

  2. 寒假ACM训练(二)

    放了假的效率明显就低起来,最近也一直在学习Ubuntu,所以一直等到今天才写. 还是在用PC. 真的十分郁闷这个LC-Display,其实从思路上是有很多.不过我最后把他当成8字,分成了七笔. 一直W ...

  3. ACM Sdut 2158 Hello World!(数学题,排序) (山东省ACM第一届省赛C题)

    题目描述 We know thatIvan gives Saya three problems to solve (Problem F), and this is the firstproblem. ...

  4. JavaScript 中常用的 正则表达式

    这编文章我来整理了一些在 javascript 中常用的正则式希望能给大家带来一些开发的灵感 //校验是否全由数字组成 function isDigit(s) { var patrn=/^[0-9]{ ...

  5. 上传图片预览 支持IE8+,FF,Chrome ,保留原图片比例

    代码及效果:链接

  6. yii2源码学习笔记(十五)

    这几天有点忙今天好些了,继续上次的module来吧 /** * Returns the directory that contains the controller classes according ...

  7. Svn与Git的区别

    把第一条理解到位思想到位了做起来才会有的放矢,其他几条都是用的时候才能体会到 1) 最核心的区别Git是分布式的,而Svn不是分布的.能理解这点,上手会很容易,声明一点Git并不是目前唯一的分布式版本 ...

  8. ajax 异步上传视频带进度条并提取缩略图

    最近在做一个集富媒体功能于一身的项目.需要上传视频.这里我希望做成异步上传,并且有进度条,响应有状态码,视频连接,缩略图. 服务端响应 { "thumbnail": "/ ...

  9. ThinkPHP Uploadify 图片上载

    从官方网站下载的Uploadify最新版本:http://www.uploadify.com/download/ jQuery库是1.7.1版本. 下载好的Uploadify目录下面的文件有: 用到的 ...

  10. Python Standard Library 学习(一) -- Built-in Functions 内建函数

    内建函数列表 Built-in Functions abs() divmod() input() open() staticmethod() all() enumerate() int() ord() ...