小行星
个人认为思维难度比较大。
看到这题,我们要想办法将其转化为最小割。
考虑到割x,y,z都能完成任务,我们将其并联,割掉其中任意一边都行。
因为割得是权,于是以权为点,而不是以节点为点。
并且要拆点。
超级源点向x连边,x向y的入口连边,y的入口向出口连边,y的出口向z连边,z向超级汇点连边。
看代码:
#include<bits/stdc++.h> using namespace std; #define inf 1e9 const int maxn=2020; const int maxm=1e5+10; int p[maxn][maxn]; int n,dep[maxn]; struct node{ int x,y,z; }a[maxm]; queue<int>q; inline int bfs(){ memset(dep,0x3f,sizeof(dep)); while(!q.empty())q.pop(); dep[0]=0; q.push(0); while(!q.empty()){ int x=q.front(); q.pop(); for(int i=0;i<=2001;i++) if(p[x][i]&&dep[i]>10000){ dep[i]=dep[x]+1; q.push(i); } } return dep[2001]<10000; } inline int dfs(int x,int lim){ if(x==2001||!lim)return lim; int ans=0; for(int i=0;i<=2001;i++) if(p[x][i]&&dep[i]==dep[x]+1){ int f=dfs(i,min(p[x][i],lim)); lim-=f;ans+=f; p[x][i]-=f;p[i][x]+=f; } return ans; } int main(){ cin>>n; for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); for(int i=1;i<=n;i++){ p[0][a[i].x]=1; p[a[i].x][a[i].y+500]=inf; p[a[i].y+500][a[i].y+1000]=1; p[a[i].y+1000][a[i].z+1500]=inf; p[a[i].z+1500][2001]=1; } int maxflow=0; while(bfs())maxflow+=dfs(0,inf); printf("%d\n",maxflow); return 0; }
深深地感到自己的弱小。