题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=6808
分析:
问题可以转化为在一个平面上求最少的直线将全部的点覆盖(直线的斜率只能为 (1) 或者 (-1)),将平面旋转 (45^。),那么直线就平行于 (x) 或 (y) 轴,对于一个点,就相当于在其横纵坐标之间连一条边,问题转化为二分图的最小顶点覆盖,求最大匹配即可。但如果直接旋转,坐标就会变成浮点数,不好处理。因此,可以转化为在 (y) 轴上的截距的匹配,注意要离散化。另外,求最大匹配不能用匈牙利算法,复杂度为:(O(n*m)),会超时,要用时间复杂度为 (O(sqrt{n}*m)) 的 (HK) 算法。用网络流处理最大匹配也可以。
代码:
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f;
const double pi=acos(-1);
vector<int>pic[N<<1];
queue<int>que;
int cx[N],cy[N],dx[N],dy[N],a[N],b[N],d[N<<1];
int dis,V,len;
bool vis[N];
int getid(int m)
{
return lower_bound(d+1,d+1+len,m)-d;
}
bool bfs()
{
while(!que.empty())
que.pop();
for(int i=1;i<=len;i++)
{
dx[i]=-1;
dy[i]=-1;
}
dis=inf;
for(int i=1;i<=len;i++)
{
if(cx[i]==-1)
{
que.push(i);
dx[i]=0;
}
}
while(!que.empty())
{
int now=que.front();
que.pop();
if(dx[now]>dis) break;
for(int i=0;i<pic[now].size();i++)
{
int t=pic[now][i];
if(dy[t]==-1)
{
dy[t]=dx[now]+1;
if(cy[t]==-1) dis=dy[t];
else
{
dx[cy[t]]=dy[t]+1;
que.push(cy[t]);
}
}
}
}
return dis!=inf;
}
int dfs(int v)
{
for(int i=0;i<pic[v].size();i++)
{
int t=pic[v][i];
if(!vis[t]&&dy[t]==dx[v]+1)
{
vis[t]=1;
if(cy[t]!=-1&&dy[t]==dis) continue;
if(cy[t]==-1||dfs(cy[t]))
{
cy[t]=v;
cx[v]=t;
return true;
}
}
}
return false;
}
int HK()
{
int ans=0;
for(int i=1;i<=len;i++)
{
cx[i]=-1;
cy[i]=-1;
}
while(bfs())
{
for(int i=1;i<=len;i++)
vis[i]=false;
for(int i=1;i<=len;i++)
{
if(cx[i]==-1&&dfs(i))
ans++;
}
}
return ans;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
int cnt=0;
scanf("%d",&n);
for(int i=1;i<=2*n;i++)
pic[i].clear();
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
d[++cnt]=(a[i]+b[i]);
d[++cnt]=(a[i]-b[i]);
}
sort(d+1,d+1+cnt);
len=unique(d+1,d+1+cnt)-d-1;
for(int i=1;i<=n;i++)
{
int t1=getid(a[i]+b[i]);
int t2=getid(a[i]-b[i]);
pic[t1].pb(t2);
}
printf("%d
",HK());
}
return 0;
}