题意:•给出两类点坐标
–一类可删除
–一类不可删除
•选出最少的行或列,删除所有要删除的点。
思路:
•首先看到坐标范围很大,第一点要做的就是离散化。
•接着,将行看成二分图的X集合,将列看成二分图的Y集合,于是,我们要删除的点,就是X连接Y的一条边。
•最后,我们要求的就是最少的点覆盖所有的边。在二分图中,最大匹配==最小点覆盖。
需要注意的地方:
•判断每一个要删除的点,如果X方向和Y方向都有不能删除的点,就是Sorry。
•
•如果只有一个方向有,则必须使用另外一个方向删除该行/列的所有点。
•
剩下的点使用二分图最大匹配
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define clr(a,b) memset(a,b,sizeof(a))
const int maxn = 1005;
struct H
{
int x,y,id,z;
}no[maxn];
bool cmp1(H a,H b){return a.x<b.x;}
bool cmp2(H a,H b){return a.y<b.y;}
int nx[maxn],ny[maxn],nz[maxn];
int mp[maxn][maxn],mm[maxn][maxn];
int vx[maxn],vy[maxn];
int cx[maxn],cy[maxn];
int vis[maxn],sign[maxn];
int cnx,cny;
int dfs(int x)
{
for(int i=0;i<cny;i++)
{
if(!vis[i]&&mp[x][i])
{
vis[i]=1;
if(sign[i] == -1||dfs(sign[i]))
{
sign[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("E.txt","r",stdin);
freopen("out.cpp","w",stdout);
#endif // ONLINE_JUDGE
int n;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++){
scanf("%d%d%d",&no[i].z,&no[i].x,&no[i].y);
no[i].id=i;
}
sort(no,no+n,cmp1);
cnx=-1;
nx[no[0].id]=++cnx;
for(int i=1;i<n;i++) {
if(no[i].x==no[i-1].x)
nx[no[i].id]=cnx;
else nx[no[i].id]=++cnx;
}
sort(no,no+n,cmp2);
cny=-1;
ny[no[0].id]=++cny;
for(int i=1;i<n;i++) {
if(no[i].y==no[i-1].y)
ny[no[i].id]=cny;
else ny[no[i].id]=++cny;
}
cnx++;
cny++;
for(int i=0;i<n;i++)
nz[no[i].id]=no[i].z;
clr(mp,0);clr(vx,0);clr(vy,0);
for(int i=0;i<n;i++) {
if(nz[i]) mp[nx[i]][ny[i]]=1;
else{
vx[nx[i]]=1;vy[ny[i]]=1;
}
}
int flag=0;
for(int i=0;i<cnx;i++){
if(vx[i]){
for(int j=0;j<cny;j++){
if(vy[j]) {if(mp[i][j]){flag=1;break;}}
}
}
if(flag) break;
}
if(flag) {printf("Sorry\n");continue;}
int ans=0;
clr(cx,0);clr(cy,0);
for(int i=0;i<cnx;i++){
if(vx[i]){
for(int j=0;j<cny;j++) if(mp[i][j]) {cy[j]=1;}
}
}
for(int i=0;i<cny;i++){
if(vy[i]){
for(int j=0;j<cnx;j++) if(mp[j][i]) {cx[j]=1;}
}
}
for(int i=0;i<cnx;i++){
if(cx[i]) {ans++;for(int j=0;j<cny;j++) if(mp[i][j])mp[i][j]=0;}
}
for(int i=0;i<cny;i++){
if(cy[i]) {
ans++;for(int j=0;j<cnx;j++) if(mp[j][i])mp[j][i]=0;
}
}
memset(sign,-1,sizeof(sign));
for(int i=0;i<cnx;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i))
ans++;
}
printf("%d\n",ans);
}
return 0;
}