Easy Delete

题目:

Description

Huicpc0215 has downloaded a lots of files in his desktop. Since there are too many files in the desktop, he wants to delete some files in the desktop. But some files can’t be deleted.


Figure 1 Messy Desktop

Each time he can choose one row or column to delete. But attention he can’t choose one row or column that has a file which can’t be deleted. Given the position of all files, please get the minimum steps for huicpc0215 to delete all files that he wants to delete.

Input

There are multiple test cases. Each test case containing:

The first line contains one integer: N (1 <= N <= 1000) ,

N lines follows. Each line contains three integers: F (0 <= F <= 1), X (-1e9 <= V <= 1e9), Y (-1e9 <= V <= 1e9). F=0 means this file can’t be delete. F=1 means this file must be deleted. And X and Y are the position of the file in the desktop.

Output

If huicpc0215 can achieve his goal, print minimum steps to achieve his goal, otherwise print “Sorry” in one line.

Sample Input

2

0 1 1

1 1 2

3

0 1 1

0 2 2

1 1 2

3

1 1 1

1 2 2

1 1 2
Sample Output

1

Sorry

2
题目大意就是给你n个点,然后下面n行,第一个数字(0或1)代表该点是否能被删除,0代表不能删除,1代表能删除,然后接下去两个整数代表其在坐标系中的位置(x,y),问你最少删除几行能够将所有的能删除(即第一个数字为1的)的点全部删除完。如果不能做到,输出sorry。

首先,不管能不能,假设所有的点都能够删除,那么我们可以建立以下模型。一个点(x,y)占据了某一行与某一列,这相当于我们把x(行)看成一个集合,y(列)看成另外一个集合,那么(x,y)这个点就是连接这两个集合的边,能够发现,这是个二分图。而要删除最少的行或者列来删除所有点,那么即求用最少的点来使覆盖所有的边,那么问题就转换成了最小顶点覆盖问题,而在二分图中, 最小顶点覆盖 = 最大匹配。模型建立好了。

而在此题中,有一些点时不可删除的,我们得做一些处理。首先点的坐标很大,得先离散化,将x和y都离散化成不同的数字,代表某一行或者某一列,然后如果该行或者该列不可以删除的话,那么就标记。然后遍历每个点,如果该点所在的行不可删除,那么我们就删除该点所在的列,将列上所有点都删除,如果是列不可删除也同理。

做完上面的工作以后,剩下的点就符合二分图的模型了,求一下最大匹配即可。

/*
 * ThinkingLion.cpp
 *
 *  Created on: 2014年11月1日
 *      Author: dell
 */
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<set>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
int n,m,k;
#define N 1005
#define ll __int64
#define p pair<int,int>
int pf[N],px[N],py[N];
int maxx,maxy;
int vis[N*2],used[N*2],match[N*2];
set<p> s[2*N];
int ans;
int Compress(int *x,int dif){								//将坐标离散化
	vector<int> v;
	for(int i=0;i<n;i++) v.push_back(x[i]);
	sort(v.begin(),v.end());			//排序(是为了使用unique) unique会将相邻重复元素移至末尾,返回一个指向不含重复元素数组的最后位置指针
	v.erase(unique(v.begin(),v.end()),v.end());	//将重复元素删除
	for(int i=0;i<n;i++) x[i]=find(v.begin(),v.end(),x[i]) - v.begin()+dif; //离散化坐标(其中,y的坐标得和x不一样,否则无法处理,y只需平移值最大x之上)
	return v.size();
}
bool Check(){				//检查是否所有点都可以删除
	int u,fg;
	for(int i=0;i<n;i++){
		if(pf[i]){	//该点可以删
			if(!used[px[i]] && !used[py[i]]) return false;	//但该点所在的行与列都不可以删除,那么该点也不可删,返回false;
			else if(!used[px[i]] || !used[py[i]]){
				if(!used[px[i]]){						//所在行不可以删
					u=py[i];
					fg=0;
				}
				else{						//所在列不可以删
					u=px[i];
					fg=1;
				}
				used[u]=false;
				set<p>::iterator it;
				for(it=s[u].begin();it!=s[u].end();it++){	//删除u所在行/列上所有的点,并将它们都标记为不可删除(这样后面就不会被再被访问到)
					int q=it->second;pf[q]=0;
					if(!fg) s[px[q]].erase(make_pair(u,q));  //行不可删,那么列是固定的
					else s[py[q]].erase(make_pair(u,q));		//列不可删,那么行是固定的
				}
				s[u].clear();		//该行/列点全部删除
				match[u]=-2;		//匹配值改为-2
				ans++;			//执行了一行/一列,ans+=1;
			}
		}
	}
	return true;
}
int dfs(int u){		//寻找增广路径
	vis[u]=1;
	set<p>::iterator it;
	for(it=s[u].begin();it!=s[u].end();it++){
		int v=it->first;
		int w=match[v];
		if(w == -1 || (w >=0 && !vis[w] &&dfs(w))){
			match[u]=v;
			match[v]=u;
			return true;
		}
	}
	return false;
}
int solve(){
	int res=0;
	for(int i=0;i<n;i++){
		if(match[i] == -1){
			memset(vis,0,sizeof vis);
			if(dfs(i)) res++;
		}
	}
	return res;
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
//	cout<<quick_mod(2,-1,N)<<endl;
	while(scanf("%d",&n)!=EOF){
		for(int i=0;i<n;i++) scanf("%d%d%d",&pf[i],&px[i],&py[i]);
		maxx = Compress(px,0);
		maxy = Compress(py,maxx);
		for(int i=0;i<maxx+maxy;i++){		//初始化
			s[i].clear();
			used[i]=true;
		}
		memset(match,-1,sizeof match);//初始化
		for(int i=0;i<n;i++){
			s[px[i]].insert(make_pair(py[i],i));
			s[py[i]].insert(make_pair(px[i],i));
			if(!pf[i]){										//若该点不可删,那么将该点所在的行和列都标记为不可删,并将其匹配置为-2
				used[px[i]]=used[py[i]]=false;
				match[px[i]]=match[py[i]]=-2;
			}
		}
		ans=0;
		if(Check()) printf("%d\n",ans+solve());
		else
			printf("Sorry\n");
	}
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值