题目描述
星云中有n颗行星,每颗行星的位置是(x,y,z)。每次可以消除一个面(即x,y或z坐标相等)的行星,但是由于时间有限,求消除这些行星的最少次数。
输入格式
第1行为小行星个数n,第2行至第n+1行为xi, yi, zi,描述第i个小行星所在的位置。
输出格式
共1行,为消除所有行星的最少次数。
输入输出样例
输入 #1复制
3
1 2 3
2 3 1
1 3 2
输出 #1复制
2
说明/提示
1≤n≤50000
1≤x,y,z≤500
很明显的,我们分别对x,y,z分别建图即可。
让x连y,y连z。对y拆点限流。
然后跑最小割,也就是最大流即可。
在大佬那里的图:
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e4+10,M=1e6+10;
int n,s,t,h[N];
int head[N],nex[M],to[M],w[M],tot=1;
inline void ade(int a,int b,int c){
to[++tot]=b; w[tot]=c; nex[tot]=head[a]; head[a]=tot;
}
inline void add(int a,int b,int c){
ade(a,b,c); ade(b,a,0);
}
inline int bfs(){
queue<int> q; q.push(s); memset(h,0,sizeof h); h[s]=1;
while(q.size()){
int u=q.front(); q.pop();
for(int i=head[u];i;i=nex[i]){
if(!h[to[i]]&&w[i]){
h[to[i]]=h[u]+1; q.push(to[i]);
}
}
}
return h[t];
}
int dfs(int x,int f){
if(x==t) return f; int fl=0;
for(int i=head[x];i&&f;i=nex[i]){
if(h[to[i]]==h[x]+1&&w[i]){
int mi=dfs(to[i],min(w[i],f));
w[i]-=mi; w[i^1]+=mi; fl+=mi; f-=mi;
}
}
if(!fl) h[x]=-1;
return fl;
}
int dinic(){
int res=0;
while(bfs()) res+=dfs(s,inf);
return res;
}
signed main(){
cin>>n; t=2010;
for(int i=1;i<=n;i++){
int x,y,z; scanf("%d %d %d",&x,&y,&z);
add(x,y+500,inf); add(y+1000,z+1500,inf);
}
for(int i=1;i<=500;i++)
add(s,i,1),add(i+500,i+1000,1),add(i+1500,t,1);
cout<<dinic()<<endl;
return 0;
}