先不管不能删的文件,我们可以把出现文件的行看作二分图的X部,列看作二分图的Y部,文件则是边。删除所有文件,其实就是求图的最小点覆盖,也就是最大匹配。于是解法就是先处理与不能删文件处在同一行、列的情况,然后跑最大匹配。
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
int n;
int x[1111];
int y[1111];
int f[1111];
map<int,int> mpx;
map<int,int> mpy;
set<int> bansx;
set<int> bansy;
vector<int> g[1111];
int matched[1111];
set<int> rx;
set<int> ry;
void init(){
mpx.clear();
mpy.clear();
rx.clear();
ry.clear();
bansx.clear();
bansy.clear();
memset(g,0,sizeof(g));
memset(matched,-1,sizeof(matched));
}
bool vis[1111];
bool dfs(int u){
for(int i=0;i<g[u].size();i++){
int v = g[u][i];
if(vis[v])continue;
vis[v] = 1;
int w = matched[v];
if(w==-1 || (dfs(w))){
matched[v] = u;
return true;
}
}
return false;
}
int main(){
while(cin>>n){
init();
for(int i=1;i<=n;i++){
scanf("%d%d%d",&f[i],&x[i],&y[i]);
if(f[i]==0){
bansx.insert(x[i]);
bansy.insert(y[i]);
}
}
bool ok = 1;
int ans = 0;
for(int i=1;i<=n;i++){
if(f[i]==0)continue;
if(bansx.count(x[i]) && bansy.count(y[i])){
ok = 0;
break;
}
if(bansx.count(x[i])){
ry.insert(y[i]);
}
if(bansy.count(y[i])){
rx.insert(x[i]);
}
}
ans = rx.size() + ry.size();
if(!ok){
cout<<"Sorry"<<endl;
continue;
}
int k = 0;
for(int i=1;i<=n;i++){
if(f[i]==1){
if(rx.count(x[i]) || ry.count(y[i]))continue;
x[k] = x[i];
y[k] = y[i];
mpx[x[i]];
mpy[y[i]];
k++;
}
}
map<int,int>::iterator it;
int xrnk = 0;
for(it=mpx.begin();it!=mpx.end();it++){
it->second = ++xrnk;
}
int yrnk = 0;
for(it=mpy.begin();it!=mpy.end();it++){
it->second = ++yrnk;
}
for(int i=0;i<k;i++){
x[i] = mpx[x[i]];
y[i] = mpy[y[i]];
g[x[i]].push_back(y[i]);
}
for(int i=1;i<=xrnk;i++){
memset(vis,0,sizeof(vis));
ans += dfs(i);
}
cout<<ans<<endl;
}
return 0;
}