zoukankan      html  css  js  c++  java
  • 【LA3487】最小割-经典模型 两种方法

    题目链接

    题意:A、B两个公司要买一些资源(他们自己买的资源不会重复),一个资源只能卖给一个公司。问最大收益。

    simple input 部分:

    54 1 //买到1就给54元

    15 2

    33 3

    2 4 5//买到4、5就给2元

    题解:这道题是很经典的模型题,在这里给出两个方法。

    方法一 把每个询问看成一个点,然后A的询问连源点,B的询问连汇点,如果AB间的某个询问有矛盾就在它们中间连一条无限大的边,ans=sum-最小割。

    // 方法一 把每个询问看成一个点,然后A的询问连源点,B的询问连汇点,如果AB间的某个
    // 询问有矛盾就在它们中间连一条无限大的边,ans=sum-最小割。
    
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<vector>
    using namespace std;
    
    const int N=300100,INF=(int)1e9;
    int s,t,len,num;
    int first[2*N],dis[2*N];
    int A[N],B[N],p1[N],p2[N];
    // bool vis[2*N];
    bool vis[3100][3100];
    struct node{
        int x,y,d,next;
    }a[6*N];
    queue<int> q;
    
    int minn(int x,int y){return x<y ? x:y;}
    int maxx(int x,int y){return x>y ? x:y;}
    
    void ins(int x,int y,int d)
    {
        a[++len].x=x;a[len].y=y;a[len].d=d;
        a[len].next=first[x];first[x]=len;
        a[++len].x=y;a[len].y=x;a[len].d=0;
        a[len].next=first[y];first[y]=len;
    }
    
    bool bfs(int st,int ed)
    {
        while(!q.empty()) q.pop();
        memset(dis,-1,sizeof(dis));
        dis[st]=0;
        q.push(st);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=first[x];i!=-1;i=a[i].next)
            {
                int y=a[i].y;
                if(dis[y]==-1 && a[i].d>0)
                {
                    dis[y]=dis[x]+1;
                    q.push(y);
                }
            }
        }
        return (dis[ed]!=-1);
    }
    
    int dfs(int x,int ed,int flow)
    {
        int r=0,p;
        if(x==ed) return flow;
        for(int i=first[x];i!=-1;i=a[i].next)
        {
            int y=a[i].y;
            if(dis[y]==dis[x]+1 && a[i].d>0)
            {
                p=minn(a[i].d,flow-r);
                p=dfs(y,ed,p);
                r+=p;
                a[i].d-=p;
                a[i^1].d+=p;
            }
        }
        if(!r) dis[x]=-1;
        return r;
    }
    
    int dinic(int st,int ed)
    {
        int ans=0;
        while(bfs(st,ed))
        {
            int p;
            while(p=dfs(st,ed,INF)) ans+=p;
        }
        return ans;
    }
    
    int main()
    {
        int T,cas=0;
        scanf("%d",&T);
        while(T--)
        {
            len=-1;
            memset(first,-1,sizeof(first));
            memset(A,0,sizeof(A));
            memset(B,0,sizeof(B));
            memset(vis,0,sizeof(vis));
            int n,m,sum=0,mx=0,num=300001;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&p1[i]);
                sum+=p1[i];
                int x;num++;
                while(1)
                {
                    char c;
                    scanf("%d%c",&x,&c);
                    A[x]=i;
                    mx=maxx(mx,x);
                    if(c=='
    ') break;
                }
            }
            scanf("%d",&m);
            s=0,t=n+m+1;
            for(int i=1;i<=m;i++)
            {
                scanf("%d",&p2[i]);
                sum+=p2[i];num++;
                int x;
                while(1)
                {
                    char c;
                    scanf("%d%c",&x,&c);
                    B[x]=i;
                    mx=maxx(mx,x);
                    if(c=='
    ') break;
                }
            }
            for(int i=1;i<=n;i++) ins(s,i,p1[i]);
            for(int i=1;i<=m;i++) ins(i+n,t,p2[i]);
            for(int i=1;i<=mx;i++)
            {
                if(!A[i]||!B[i]||vis[A[i]][B[i]]) continue;
                vis[A[i]][B[i]]=true;
                ins(A[i],B[i]+n,INF);
            }
            printf("Case %d:
    ",++cas);
            printf("%d
    ",sum-dinic(s,t));
            if(T) printf("
    ");
        }
        return 0;
    }
    方法一

    方法二:对于每个询问,新建一个点x,如果是A就源点连向这个点,流量为价钱p,然后x连向这个询问所要求买的资源c[i],流量为INF。

    如果是B则反过来,连向汇点。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<vector>
    using namespace std;
    
    const int N=300100,INF=(int)1e9;
    int s,t,len,num;
    int first[2*N],dis[2*N];
    int A[N],B[N];
    bool vis[3100][3100];
    struct node{
        int x,y,d,next;
    }a[6*N];
    queue<int> q;
    
    int minn(int x,int y){return x<y ? x:y;}
    int maxx(int x,int y){return x>y ? x:y;}
    
    void ins(int x,int y,int d)
    {
        a[++len].x=x;a[len].y=y;a[len].d=d;
        a[len].next=first[x];first[x]=len;
        a[++len].x=y;a[len].y=x;a[len].d=0;
        a[len].next=first[y];first[y]=len;
    }
    
    bool bfs(int st,int ed)
    {
        while(!q.empty()) q.pop();
        memset(dis,-1,sizeof(dis));
        dis[st]=0;
        q.push(st);
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=first[x];i!=-1;i=a[i].next)
            {
                int y=a[i].y;
                if(dis[y]==-1 && a[i].d>0)
                {
                    dis[y]=dis[x]+1;
                    q.push(y);
                }
            }
        }
        return (dis[ed]!=-1);
    }
    
    int dfs(int x,int ed,int flow)
    {
        int r=0,p;
        if(x==ed) return flow;
        for(int i=first[x];i!=-1;i=a[i].next)
        {
            int y=a[i].y;
            if(dis[y]==dis[x]+1 && a[i].d>0)
            {
                p=minn(a[i].d,flow-r);
                p=dfs(y,ed,p);
                r+=p;
                a[i].d-=p;
                a[i^1].d+=p;
            }
        }
        if(!r) dis[x]=-1;
        return r;
    }
    
    int dinic(int st,int ed)
    {
        int ans=0;
        while(bfs(st,ed))
        {
            int p;
            while(p=dfs(st,ed,INF)) ans+=p;
        }
        return ans;
    }
    
    int main()
    {
        int T,cas=0;
        scanf("%d",&T);
        while(T--)
        {
            len=-1;
            memset(first,-1,sizeof(first));
            memset(A,0,sizeof(A));
            memset(B,0,sizeof(B));
            memset(vis,0,sizeof(vis));
            int n,m,p,sum=0,mx=0,num=300001;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&p);
                sum+=p;
                int x;num++;
                ins(0,num,p);
                while(1)
                {
                    char c;
                    scanf("%d%c",&x,&c);
                    ins(num,x+1,INF);
                    if(c=='
    ') break;
                }
            }
            scanf("%d",&m);
            s=0,t=1;
            for(int i=1;i<=m;i++)
            {
                scanf("%d",&p);
                sum+=p;num++;
                ins(num,t,p);
                int x;
                while(1)
                {
                    char c;
                    scanf("%d%c",&x,&c);
                    ins(x+1,num,INF);
                    if(c=='
    ') break;
                }
            }
            for(int i=1;i<=n;i++) ins(s,i,p1[i]);
            for(int i=1;i<=m;i++) ins(i+n,t,p2[i]);
            for(int i=1;i<=mx;i++)
            {
                if(!A[i]||!B[i]||vis[A[i]][B[i]]) continue;
                vis[A[i]][B[i]]=true;
                ins(A[i],B[i]+n,INF);
            }
            printf("Case %d:
    ",++cas);
            printf("%d
    ",sum-dinic(s,t));
            if(T) printf("
    ");
        }
        return 0;
    }
    方法二
  • 相关阅读:
    caffe:mac10.12安装caffe的步骤
    查找两个链表的共同子链表
    golang:1.并发编程之互斥锁、读写锁详解
    git问题汇总
    有用的技术工具
    maven 安装本地jar包到本地maven仓库
    win7下Hadoop学习 之 Cygwin下载、安装、配置
    简单目录备份脚本
    2021年01月28日微博热搜汇总
    2021年01月26日微博热搜汇总
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5516479.html
Copyright © 2011-2022 走看看