Go Running(坐标旋转,二分图最小点覆盖)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6808
题意:若干人在 x 轴上跑步,每个人的开始时间、停止时间、跑的方向、起跑位置都是未知的,但是速度一定为 1m / s,然后有一些机器,记录了 n 条记录,每条记录包含两个信息:xi,ti;表示在 ti 时刻在 xi 未知有一个人经过,问最少有多少人参加跑步。
Input
T(1 <= T <= 100)组样例,每组样例一个 n (1 <= n <= 1e5) 表示共有 n 条记录,然后 n 行,每行两个值 ti,xi (1 ≤ ti, xi ≤ 1e9)。
Output
输出最少有多少人参加跑步
Sample Input
2
3
1 1
2 2
3 1
3
1 1
2 2
3 3
Sample Output
2
1
思路:首先画出 x - t 图像,每个人跑出来的直线一定是斜率为 -1 或 1 的直线,那么问题转化为最少用几条斜率为 -1 或 1 的直线覆盖所有点,这与二分图的最小点覆盖问题很相似,但我们无法建图,所以我们 45° 旋转坐标系,此时一个点最后的运动直线或平行于 x 轴或平行与 y 轴,假设点(x, y)旋转后的坐标为(x1, y1),那么我们把 x1 当做二分图左边的点,y1当做二分图右边的点,两点建边,因为二分图的最小点覆盖 = 二分图最大匹配,所以我们对这个图跑一遍二分图匹配问题就解决了。
二分图总结【最大匹配、最小点覆盖、最少路径覆盖和最大独立集】
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #include<stack> #include<vector> #include<set> #include<map> #include<unordered_map> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int N = 200010; int n, uN, tot; vector<int> G[N]; int Mx[N], My[N]; int dx[N], dy[N]; int dis; bool used[N]; unordered_map<double, int> mx, my; bool SearchP() { queue<int> Q; dis = inf; memset(dx, -1, sizeof(dx)); memset(dy, -1, sizeof(dy)); for(int i = 0; i < uN; i++) { if(Mx[i] == -1) { Q.push(i); dx[i] = 0; } } while(!Q.empty()) { int u = Q.front(); Q.pop(); if(dx[u] > dis) { break; } int sz = (int)G[u].size(); for(int i = 0; i < sz; i++) { int v = G[u][i]; if(dy[v] == -1) { dy[v] = dx[u] + 1; if(My[v] == -1) { dis = dy[v]; } else { dx[My[v]] = dy[v] + 1; Q.push(My[v]); } } } } return dis != inf; } bool dfs(int u) { int sz = (int)G[u].size(); for(int i = 0; i < sz; i++) { int v = G[u][i]; if(!used[v] && dy[v] == dx[u] + 1) { used[v] = true; if(My[v] != -1 && dy[v] == dis) { continue; } if(My[v] == -1 || dfs(My[v])) { My[v] = u; Mx[u] = v; return true; } } } return false; } int MaxMatch() { int res = 0; memset(Mx, -1, sizeof(Mx)); memset(My, -1, sizeof(My)); while(SearchP()) { memset(used, false, sizeof(used)); for(int i = 0; i < uN; i++) { if(Mx[i] == -1 && dfs(i)) { res++; } } } return res; } int main() { int t; int u, v, x, y; double z = sqrt(2) / 2; scanf("%d", &t); while(t--) { mx.clear(); my.clear(); uN = 0; scanf("%d", &n); tot = n; for(int i = 0; i <= n; i++) G[i].clear(); for(int i = 1; i <= n; i++) { scanf("%d %d", &x, &y); double xx = z * (x + y); double yy = z * (y - x); if(!mx.count(xx)) mx[xx] = uN++; if(!my.count(yy)) my[yy] = ++tot; u = mx[xx]; v = my[yy]; G[u].push_back(v); } printf("%d\n", MaxMatch()); } return 0; }

浙公网安备 33010602011771号