题意:给出N个元组(x, y)问最多需要多少个初始状态才能转移到这样,一个元组(x,y)可以一直向右转移(x+1, y+1)...(x+i, y+i)或者一直向左转移(x+i, y-i)。n<1e5, x,y<1e9
题解:选择最少的直线,能够包括所有给定的点(x,y),把斜率1和-1的直线分别作为二分图u,v部分,当前有(x,y)即对两条直线加边,求的即是二分图的最小顶点覆盖。
二分图最小顶点覆盖定义:假如选了一个点就相当于覆盖了以它为端点的所有边。最小顶点覆盖就是选择最少的点来覆盖所有的边。
HK算法:
#include <bits/stdc++.h> #define IO_read ios::sync_with_stdio(false);cin.tie(0) #define fre freopen("C:\in.txt", "r", stdin) #define _for(i,a,b) for(int i=a; i< b; i++) #define _rep(i,a,b) for(int i=a; i<=b; i++) #define inf 0x3f3f3f3f #define lowbit(a) ((a)&-(a)) using namespace std; typedef long long ll; template <class T> void read(T &x) { char c; bool op=0; while(c=getchar(), c<'0'||c>'9') if(c=='-') op=1; x=c-'0'; while(c=getchar(), c>='0'&&c<='9') x=x*10+c-'0'; if(op) x=-x; } template <class T> void write(T x) { if(x<0) putchar('-'), x=-x; if(x>=10) write(x/10); putchar('0'+x%10); } const int maxn=1e5+5; unordered_map<int, int> line1, line2; int T, n; /* //hungry算法复杂度:VE TEL vector<int> g[maxn]; int un, vn; int linker[maxn], used[maxn]; bool dfs(int u) { for(auto &v: g[u]){ if(!used[v]){ used[v]=true; if(linker[v]==-1 || dfs(linker[v])){ linker[v]=u; return true; } } } return false; } int hungry() { int res=0; memset(linker, -1, sizeof(linker)); for(int u=1; u<=un; u++){ memset(used, 0, sizeof(used)); if(dfs(u)) res++; } return res; } */ // hk算法时间复杂度sqrt(V)*E vector<int> g[maxn]; int un, vn; int linker[maxn], used[maxn]; int mx[maxn], my[maxn], dx[maxn], dy[maxn], dis; bool search_path() { queue<int> que; dis=inf; memset(dx, -1, sizeof(dx)); memset(dy, -1, sizeof(dy)); for(int u=1; u<=un; u++){ if(mx[u]==-1) que.push(u), dx[u]=0; } while(!que.empty()) { int u=que.front(); que.pop(); if(dx[u]>dis) break; for(auto &v: g[u]){ if(dy[v]==-1){ dy[v]=dx[u]+1; if(my[v]==-1) dis=dy[v]; else dx[my[v]]=dy[v]+1, que.push(my[v]); } } } return dis!=inf; } bool dfs(int u) { for(auto &v: g[u]) { 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 hopcroft_karp() { int res=0; memset(mx, -1, sizeof(mx)); memset(my, -1, sizeof(my)); while(search_path()){ memset(used, 0, sizeof(used)); for(int u=1; u<=un; u++) if(mx[u]==-1 && dfs(u)) res++; } return res; } int main() { read(T); while(T--) { read(n); un=vn=0; _rep(i, 1, n) g[i].clear(); line1.clear(), line2.clear(); int x, y; _rep(i, 1, n){ read(x), read(y); int k1=y-x, k2=y+x; if(!line1[k1]) line1[k1]=++un; if(!line2[k2]) line2[k2]=++vn; g[line1[k1]].push_back(line2[k2]); } //printf("%d ", hungry()); printf("%d ", hopcroft_karp()); } return 0; }