小行星

个人认为思维难度比较大。

看到这题,我们要想办法将其转化为最小割。

考虑到割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;
}

深深地感到自己的弱小。

 

posted @ 2020-03-06 20:46  syzf2222  阅读(179)  评论(0编辑  收藏  举报