zoukankan      html  css  js  c++  java
  • 2020杭电多校第四场 hdu6808 Go Running

    还算比较经典的一道题吧
    个人赛上丢给 19 级的做本是想让他们对网络流二分图多一分掌握
    没想到全给我爆零了
    赛后让 vv 写题解 vv 也是隔了几天都没有动静
    好吧又得我来了

    题目链接

    点我跳转

    题目大意

    给定一个无现场的跑道和 N 个监控点 , 跑道上有若干个人在跑步
    每个人的运行速度为 1m/s , 起始位置、起始时间、运动方向未知
    其中第 i 个监控点会告诉你时间为 ti 时 di 的位置至少有一个人
    问这个跑道上最少有多少人在跑步

    解题思路

    设每个监控点只有一个人,那么最多有 N 个人 , 而其中一些监控捕捉到的人可能是同一个人
    因此我们可以将每个监控拍到的人的运行轨迹用方程表示出来来判断是否会是同一个人

    假设一组样例为:
    5
    1 1 
    2 2 
    3 1 
    3 4 
    4 3 
    

    我们先将每个监控下的人的信息在平面直角坐标系中表示出来,如下

    在这里插入图片描述

    由于每个人的运行速率为 1m/s , 方向未知 , 于是我们可以用下图表示所有可能的运行轨迹

    在这里插入图片描述

    其中黑色的直接正方向的运动轨迹 , 红色的直线表示负方向的运动轨迹

    那么现在题目就可以转换成最少需要多少条直线 , 使得这些直线可以覆盖所有的点

    我们再将整个坐标系旋转45°,得到下图
    在这里插入图片描述
    此时题目就变为最少需要多少根横线或者竖线 , 使得这些线可以覆盖所有点
    这不就是经典的二分图最小点覆盖嘛 ?
    如果你没看出来 , 我们可以再进一步转换

    设: 
       A 的横坐标为 X1, 纵坐标为 Y1
       B 的横坐标为 X2, 纵坐标为 Y1
       C 的横坐标为 X2, 纵坐标为 Y2
       D 的横坐标为 X3, 纵坐标为 Y3
       E 的横坐标为 X3, 纵坐标为 Y4
    

    将点化边 , 将边化点
    在这里插入图片描述
    因为只需要一条边的端点即可覆盖这条边 , 而我们要覆盖所有边
    很显然 , 最小点覆盖问题(如果到这你还没懂 , 建议先把二分图的基础概念学了)
    剩下的就是建图跑 dinic 或者 带时间戳优化的匈牙利了

    AC_Code(dinic)

    #include<bits/stdc++.h>
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define int long long
    #define ll long long
    using namespace std;
    template<typename T>void read(T &res)
    {
      bool flag=false;
      char ch;
      while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
      for(res=ch-48; isdigit(ch=getchar()); res=(res<<1)+(res<<3)+ch - 48);
      flag&&(res=-res);
    }
    template<typename T>void Out(T x)
    {
      if(x<0)putchar('-'),x=-x;
      if(x>9)Out(x/10);
      putchar(x%10+'0');
    }
    const int N = 3e5 + 10;
    const int Max = 3e5 + 10;
    struct Dinic
    {
      struct Edge
      {
          int to, nex, flow;
      } edge[Max << 1];
      int n, m, s, t;
      int head[Max], TOT;
      int dis[Max] , cur[Max];
      void init(int nn , int ss , int tt)
      {
          this->n = nn , this->s = ss , this->t = tt;
          TOT = 1;
          for(int i = 0 ; i <= nn + 1 ; i ++) head[i] = 0;
      }
      void add_edge(int u , int v , int flow)
      {
          edge[++ TOT].nex = head[u];
          edge[TOT].to = v;
          edge[TOT].flow = flow;
          head[u] = TOT;
          edge[++ TOT].nex = head[v];
          edge[TOT].to = u;
          edge[TOT].flow = 0;
          head[v] = TOT;
      }
      bool bfs()
      {
          queue<int>que;
          memset(dis, -1, (n + 1) * sizeof(int));
          dis[s] = 0;
          que.push(s);
          while(!que.empty())
          {
              int u = que.front();
              que.pop();
              for(int i = head[u]; i; i = edge[i].nex)
              {
                  int v = edge[i].to;
                  if(dis[v] == -1 && edge[i].flow > 0)
                  {
                      dis[v] = dis[u] + 1;
                      que.push(v);
                  }
              }
          }
          return dis[t] != -1;
      }
      int dfs(int u, int flow_in)
      {
          if(u == t) return flow_in;
          int flow_out = 0;
          for(int i = cur[u]; i; i = edge[i].nex)
          {
              cur[u] = i;
              int v = edge[i].to;
              if(dis[v] == dis[u] + 1 && edge[i].flow > 0)
              {
                  int flow_part = dfs(v, min(flow_in, edge[i].flow));
                  if(!flow_part)continue;
                  flow_in -= flow_part;
                  flow_out += flow_part;
                  edge[i].flow -= flow_part;
                  edge[i ^ 1].flow += flow_part;
                  if(!flow_in) break;
              }
          }
          return flow_out;
      }
      int dinic()
      {
          int maxflow = 0;
          while(bfs())
          {
              for(int i = 0; i <= n ; i ++) cur[i] = head[i];
              maxflow += dfs(s, 0x3f3f3f3f);
          }
          return maxflow;
      }
    } DI;
    map<int , int> c1 , c2;
    map<pair<int , int> , int>mp;
    int x[N] , y[N];
    signed main()
    {
      int T = 1;
      read(T);
      while(T --)
      {
          int n , cnt = 0;
          mp.clear();
          c1.clear() , c2.clear();
          read(n);
          rep(i , 1 , n) read(x[i]) , read(y[i]);
          int s = 0 , t = 2 * n + 1;
          DI.init(t , s , t);
          rep(i , 1 , n)
          {
              int tx = x[i] + y[i];
              int ty = y[i] - x[i];
              if(!c1[tx]) c1[tx] = ++ cnt , DI.add_edge(s , cnt , 1);
              if(!c2[ty]) c2[ty] = ++ cnt , DI.add_edge(cnt , t , 1);
              pair<int , int> now = make_pair(tx , ty);
              if(mp[now]) continue ;
              mp[now] = 1;
              DI.add_edge(c1[tx] , c2[ty] , 1);
          }
          Out(DI.dinic()) , puts("");
      }
      return 0;
    }
    
  • 相关阅读:
    poj 3071 Football (概率dp)
    CF1408G Clusterization Counting
    2-sat
    线段树优化建图
    SP5971 LCMSUM
    [NOI2020]命运
    SP19149 INS14H
    Atcoder ARC-068
    CF908G New Year and Original Order
    (四)、Fiddler打断点
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/13515518.html
Copyright © 2011-2022 走看看