AC日记——小行星 洛谷 P2711
题目背景
pid=3437
题目描述
星云中有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,y拆点后再连z;
来,上代码:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define maxn 505 using namespace std; struct EdgeType { int to,next,flow; }; struct EdgeType edge[maxn*500]; int if_z,n,cnt=1,head[maxn*6],s=0,t=maxn*6-1; int deep[maxn*6]; char Cget; inline void in(int &now) { now=0,if_z=1,Cget=getchar(); while(Cget>'9'||Cget<'0') { if(Cget=='-') if_z=-1; Cget=getchar(); } while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } now*=if_z; } inline void edge_add(int u,int v,int w) { edge[++cnt].to=v,edge[cnt].flow=w,edge[cnt].next=head[u],head[u]=cnt; edge[++cnt].to=u,edge[cnt].flow=0,edge[cnt].next=head[v],head[v]=cnt; } bool BFS() { memset(deep,-1,sizeof(deep)); queue<int>que;que.push(s);deep[s]=0; while(!que.empty()) { int pos=que.front();que.pop(); for(int i=head[pos];i;i=edge[i].next) { if(deep[edge[i].to]<0&&edge[i].flow>0) { deep[edge[i].to]=deep[pos]+1; if(edge[i].to==t) return true; que.push(edge[i].to); } } } return false; } int flowing(int now,int flow) { if(now==t||flow==0) return flow; int oldflow=0; for(int i=head[now];i;i=edge[i].next) { if(deep[edge[i].to]!=deep[now]+1||edge[i].flow==0) continue; int pos=flowing(edge[i].to,min(flow,edge[i].flow)); flow-=pos; oldflow+=pos; edge[i].flow-=pos; edge[i^1].flow+=pos; if(flow==0) return oldflow; } return oldflow; } int dinic() { int pos=0; while(BFS()) pos+=flowing(s,0x7ffffff); return pos; } int main() { in(n);int x,y,z; for(int i=1;i<=500;i++)//s x y y z t { edge_add(s,i,1); edge_add(i+maxn+maxn+maxn,t,1); edge_add(i+maxn,i+maxn+maxn,1); } while(n--) { in(x),in(y),in(z); edge_add(x,y+maxn,1); edge_add(y+maxn+maxn,z+maxn+maxn+maxn,1); } printf("%d\n",dinic()); return 0; }