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;
}
posted @ 2020-08-17 07:11  GsjzTle  阅读(206)  评论(0编辑  收藏  举报