最近做了一下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. ios专题 -动画

    知识点 : 1)ios 核心动画的基础是图层.图层的基础是CALayer,它是所有核心图层类的父类. 2)CATransaction是核心动画类负责协调多个动画原子显示更新.事务支持嵌套使用. 3)图 ...

  2. [转载] java中byte数组与int,long,short间的转换

    文章转载自http://blog.csdn.net/leetcworks/article/details/7390731 package com.util; /** * * <ul> * ...

  3. 解决打不开jar包

    Java应用程序jar文件可以由 JVM(Java虚拟机)直接执行,只要操作系统安装了JVM便可以运行作为Java应用程序的jar文件,其跨平台特性使得很多工具软件都用jar方式来部署分发,比如用于H ...

  4. PowerDesigner 的几个使用技巧

    1.  生成sql脚本 Database→Generate Database 选择要输出的文件路径,即文件存储路径,并根据需要修改文件名,单击确定后便会生成sql脚本.   在Options选项卡里, ...

  5. 一些static_cast const_cast

    static_cast:干杂活的,那三个都有各自的专有用途,那三个不做的都由这个转型符来做,只要它能做的,用C语法的强制类型转换运算符也一定能够完成:但话又说回来了,C强制类型转换能做的,它可不一定都 ...

  6. ExecuteReader

    最近在做winform的编程,想到一真没有使用过ExecuteReader.可能以前以后它的用户不大,或者 不大好用,故没有用过.今天在这里将学习记录写下来,供读者参考: 1.MSDN上说:Sends ...

  7. .Net C/S系统开发框架(楚楚原创)

    C/S系统开发框架-企业版 V4.0 (Enterprise Edition) 简介: http://www.csframework.com/cs-framework-4.0.htm 视频下载: 百度 ...

  8. 隐藏input边框(ie6、ie7)

    去掉元素的边框,我们一贯使用border:none; 但在ie6.ie7下的input[type=text]元素,并没有去掉. 两种解决方案: 1. border:none; 并设置背景backgro ...

  9. 关于Memcache使用的工具类

    分布式缓存有它自己的好处 . 下面的 ConstValue.sessionId  是一个常量 public static readonly string sessionId = "sessi ...

  10. ios8新特性widget开发-b

    os8发布已经有一段时间了,伴随着ios8同时也出现了许多新的特性,ios系统将会越来越开放,这是好事.其中一个新特性就是在下拉通知栏里加入了个性的widget,开发者可以自己定义widget的样式内 ...