2020杭电多校赛第四场1007 Go Running(hdu6808)

1007 Go Running(hdu6808)

题意:有一条无限长的跑道,有一些人正在以1m/s的速度匀速跑步,有一台检测机在 t i t_i ti检测到有同学在 x i x_i xi的位置,询问最少有多少个人在跑步。

解法:首先可以建立一个直角坐标系,横坐标代表时间,纵坐标代表位置,对于1m/s的匀速运动,那么一个人的运动轨迹在这样一个坐标系中斜率肯定是1或-1,那么题意就可以转换成将这些点斜率为1和-1的直线画出来,之后再看经过所有点的最少直线。
在这里插入图片描述
如果将这个图顺时针转动45度,可以想到这是二分图匹配的经典问题,最小点覆盖=最大匹配,这里我用了网络流的方法实现,建立超级源点和超级汇点。具体建边方式就是源点连向所有涉及到的行权值为1(注意重复的不叠加),所有涉及到的列连向汇点权值为1(注意重复不叠加),再对于每个点行和列建一条权值为1的边,再跑一边最大流就行。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int M = 2e5+10;
const int INF = 0x3f3f3f3f;
struct xx {
    
    
  int x, y, a, b, lx, ly;
}p[N];
bool cmp1(const xx &p1, const xx &p2) {
    
    
  return p1.a < p2.a;
}
bool cmp2(const xx &p1, const xx &p2) {
    
    
  return p1.b > p2.b;
}

struct node {
    
    
  int to, dis, next;
}Ed[M*2];
int head[M], cur[M], d[M], cnt = 1;
int tot, lst, s, t;
void Add(int from, int to, int dis) {
    
     
  Ed[++cnt] = node {
    
    to, dis, head[from]};
  head[from] = cnt; 
  Ed[++cnt] = node {
    
    from, 0, head[to]};
  head[to] = cnt; 
}  
bool bfs() {
    
    
  memset(d, -1, sizeof(d));
  queue<int>q;q.push(s);
  int u, _new;
  d[s] = 0;
  while(!q.empty()) {
    
    
    u = q.front(); q.pop();
    for(int c_e = head[u]; c_e != -1; c_e = Ed[c_e].next) {
    
    //增广路 
      _new = Ed[c_e].to;
      if(d[_new] == -1 && Ed[c_e].dis > 0) {
    
    
        d[_new] = d[u] + 1;
        q.push(_new);
      }
    }
  }
  return (d[t] != -1);
}
int dfs(int u, int flow) {
    
    
	//cout << u << " " << flow << endl;
  if(u == t) return flow;
  int _flow = 0, __flow;
  for(int &c_e = cur[u]; c_e != -1; c_e = Ed[c_e].next) {
    
    //当前弧优化 
    int v = Ed[c_e].to;
    if(d[v] == d[u] + 1 && Ed[c_e].dis > 0) {
    
    
      __flow = dfs(v, min(flow, Ed[c_e].dis));
      flow -= __flow;
      Ed[c_e].dis -= __flow;
      _flow += __flow;
      Ed[c_e^1].dis += __flow;
      if(!flow) break;
    }
  }
  if(!_flow) d[u] = -1;
  return _flow;
}
void dinic() {
    
    
  int max_flow = 0;
  while(bfs()) {
    
    
    for(int i = 0; i <= t; ++i) cur[i] = head[i];
    max_flow += dfs(s, INF);
  }
  printf("%d\n", max_flow);
}

int vis[M];
int main() {
    
    
  int T; scanf("%d", &T);
  int n;
  while(T--) {
    
    
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
    
    
      scanf("%d%d", &p[i].x, &p[i].y);
      p[i].a = p[i].x + p[i].y;
      p[i].b = p[i].y - p[i].x;
    }
    
    sort(p+1, p+n+1, cmp1);
    tot = 1, lst = p[1].a;
    p[1].ly = tot;
    for(int i = 2; i <= n; ++i) {
    
    
      if(p[i].a == lst) p[i].ly = tot;
      else p[i].ly = ++tot;
      lst = p[i].a; 
    }
    sort(p+1, p+n+1, cmp2);
    lst = p[1].b;
    p[1].lx = ++tot;
		for(int i = 2; i <= n; ++i) {
    
    
      if(p[i].b == lst) p[i].lx = tot;
      else p[i].lx = ++tot;
      lst = p[i].b;
    }
    
    //建边 
    cnt = 1;
		s = 0; t = tot+1;
    for(int i = 0; i <= t; ++i) head[i] = -1, vis[i] = 0;
		for(int i = 1; i <= n; ++i) {
    
    
    	if(!vis[p[i].lx]) Add(s, p[i].lx, 1), vis[p[i].lx] = 1;
    	Add(p[i].lx, p[i].ly, 1);
			if(!vis[p[i].ly]) Add(p[i].ly, t, 1), vis[p[i].ly] = 1; 
		}
    
    dinic();
  } 
  return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_43408978/article/details/109075171