zoukankan      html  css  js  c++  java
  • 来更新一篇blog吧

    最近做了一下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: }
  • 相关阅读:
    【Demo 0035】获取窗体状态
    【Demo 0030】获取其他进程窗体信息(防SPY++)
    【Demo 0034】窗体支持文件拖拽
    【Demo 0036】Window层窗体
    【Demo 0032】遍历子窗体
    二维数组定义以及动态分配空间 (转)
    Visual Studio 2008 环境变量的配置(dll加载方式) [转]
    修改MFC标题栏上的图标
    VC环境下的头文件包含(转)
    VC++单选按钮控件(Ridio Button)的使用(转载)
  • 原文地址:https://www.cnblogs.com/qoshi/p/3568436.html
Copyright © 2011-2022 走看看