整理一下最近做过的题。从后往前发好了。
星云中有n颗行星,每颗行星的位置是(x,y,z)。每次可以消除一个面(即x,y或z坐标相等)的行星,但是由于时间有限,求消除这些行星的最少次数。
突然发现自己不会最小割= =。考虑一下二维的情况,把坐标拆开,一对坐标连边跑最大流。
为什么是对的。代价->次数->割掉一条边。割边后的S集T集是都消除过的,所以最小割即为答案。
三维情况如上法把x,y,z相连发现y会重复使用,拆点限制流量。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+5;
const int INF=1e9+7;
struct edge{
int to,next,w;
}e[MAXN<<2];
int n,m,s,t;
int cur[MAXN],head[MAXN],cnt=1;
inline void add(int u,int v,int w){
e[++cnt]=(edge){v,head[u],w},head[u]=cnt;
e[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
queue<int>q;
int dep[MAXN];
bool bfs(int x){
memset(dep,0,sizeof(dep));
q.push(x);dep[x]=1;
while(q.size()){
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].next){
int v=e[i].to,w=e[i].w;
if(!dep[v]&&w){
dep[v]=dep[u]+1;q.push(v);
}
}
}
if(!dep[t])return 0;
return 1;
}
int dfs(int u,int flow){
if(u==t||flow==0)return flow;
for(int &i=cur[u];i;i=e[i].next){
int v=e[i].to,w=e[i].w;
if(dep[v]==dep[u]+1&&w){
int tem=dfs(v,min(flow,w));
if(tem){
e[i].w-=tem;e[i^1].w+=tem;return tem;
}
}
}
return 0;
}
int dinic(){
int ans=0;
while(bfs(s)){
for(int i=s;i<=t;i++)cur[i]=head[i];
while(int d=dfs(s,INF))ans+=d;
}
return ans;
}
int jl[505],num=0;
bool vis1[505],vis2[505],vis3[505];
int main(){
memset(vis1,0,sizeof(vis1));
memset(vis2,0,sizeof(vis2));
memset(vis3,0,sizeof(vis3));
int x,y,z;
scanf("%d",&n);
s=0,t=2001+n;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x,&y,&z);
if(!vis1[x])vis1[x]=1,add(s,x,1);
if(!vis3[z])vis3[z]=1,add(1500+z,t,1);
if(!vis2[y])vis2[y]=1,add(500+y,1000+y,1);
add(x,500+y,1);add(1000+y,1500+z,1);
}
cout<<dinic();
return 0;
}