2020杭电多校第四场 Go Running(网络流,二分图匹配)

Problem Description
Zhang3 is the class leader. Recently she’s implementing a policy about long-distance running. This forces every student in her class to take a run.

There is a main road in the school from west to east, which can be regarded as an infinite axis, and its positive direction is east. Positions on the road are represented with numbers. In order to complete the task, each student must run along the main road. Each student can decide the following things:

  • The time to start running.
  • The time to finish running.
  • The position to start running.
  • The direction of running, which is either west or east.

Once these things are decided, the student will appear at the starting position on the road at the start time, then start running in the chosen direction at a speed of 1m/s. The student disappears at the finish time. Each student will only run once.

Zhang3 knows that some students are not following her policy, so she set up some monitors. According to technical issues, the monitors can only report that there’s at least one student at a certain place at a certain time. Finally Zhang3 received n reports.

Help Zhang3 determine the minimum possible number of students who have run.

Input
The first line of the input gives the number of test cases, T(1≤T≤100). T test cases follow.

For each test case, the first line contains an integer n(1≤n≤105), the number of reports.

Then n lines follow, the ith of which contains two integers ti,xi(1≤ti,xi≤109), representing that there’s at least one student at position xi(m) at time ti(s).

The sum of n in all test cases doesn’t exceed 5×105.

Output
For each test case, print a line with an integer, representing the minimum number of students who have run.

Sample Input
2
3
1 1
2 2
3 1
3
1 1
2 2
3 3

Sample Output
2
1

Source
2020 Multi-University Training Contest 4

题意:
每个车可以在任意时间出发,任意地点出发,指定任意方向,且速度相同。
告诉你某个时刻某个位置上有车,求最少有多少车。

思路:
因为要尽量将车合并,所以相同的车肯定满足出发时间、位置、方向相同。则不妨设出发时间都为0。
对于时刻 t t ,位置为 x x 的车,可以有两个起始位置, x t x-t x + t x+t ,同时会对应两个起始方向。

每个车可以选个一个起点和其对应的方向,要求最后所选的点最少。
这实际就是最小点覆盖问题,等价于二分图最大匹配。

1e5的数据范围跑网络流,我是没想到的XD。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include <map>

using namespace std;
typedef long long ll;
const int inf = 1 << 29, N = 200010, M = 600010;
int head[N], ver[M], edge[M], Next[M], d[N];
int n, m, s, t, tot;
ll maxflow;
queue<int> q;

void add(int x, int y, int z) {
    ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
    ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
}

bool bfs() { // 在残量网络上构造分层图
    memset(d, 0, sizeof(d));
    while (q.size()) q.pop();
    q.push(s); d[s] = 1;
    while (q.size()) {
        int x = q.front(); q.pop();
        for (int i = head[x]; i; i = Next[i])
            if (edge[i] && !d[ver[i]]) {
                q.push(ver[i]);
                d[ver[i]] = d[x] + 1;
                if (ver[i] == t) return 1;
            }
    }
    return 0;
}

int dinic(int x, int flow) { // 在当前分层图上增广
    if (x == t) return flow;
    int rest = flow, k;
    for (int i = head[x]; i && rest; i = Next[i])
        if (edge[i] && d[ver[i]] == d[x] + 1) {
            k = dinic(ver[i], min(rest, edge[i]));
            if (!k) d[ver[i]] = 0; // 剪枝,去掉增广完毕的点
            edge[i] -= k;
            edge[i ^ 1] += k;
            rest -= k;
        }
    return flow - rest;
}

map<pair<int,int>,int>mp;
map<ll,int>mp2;

void init() {
    tot = 1;
    memset(head,0,sizeof(head));
    maxflow = 0;
    mp.clear();mp2.clear();
}

int main() {
    int T;scanf("%d",&T);
    while(T--) {
        init();
        scanf("%d",&n);
        //    cin >> n >> m >> e;
        s = 0,t = 2 * n + 1;
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            int tim,x;
            scanf("%d%d", &tim, &x);
            ll x1 = x - tim;
            ll x2 = x + tim + 1e10;
            if(!mp2[x1]) mp2[x1] = ++cnt;
            if(!mp2[x2]) mp2[x2] = ++cnt;
            x1 = mp2[x1];x2 = mp2[x2];
            
            if(!mp[{s,x1}]) {
                add(s,x1,1);
                mp[{s,x1}] = 1;
            }
            if(!mp[{x2,t}]) {
                add(x2,t,1);
                mp[{x2,t}] = 1;
            }
            
            if(!mp[{x1,x2}]) {
                add(x1, x2, 1);
                mp[{x1,x2}] = 1;
            }
            
        }
        
        int flow = 0;
        while (bfs())
            while (flow = dinic(s, inf)) maxflow += flow;
        cout << maxflow << endl;
        
    }
}


猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/107828354