UVALive-3487 Duopoly(最小割)

题目大意:有两家公司都想向政府申请某些资源的使用权,并且他们都提供了一些申请列表,列表中含有申请费用和资源种类,同一家公司的申请列表之间不含有重复的资源。政府只可以完整地接受和拒绝谋一份申请列表,问政府的最大收益是多少。

题目分析:如果两家公司的申请之间没有任何矛盾,那么最大的收益就是所有的申请费用之和。如果某些列表之间有矛盾,那么就需要用最小的代价使两家公司的申请没有任何矛盾。将每一条申请视作一个点,增加源点s和汇点t,从s向甲公司的每一条申请连一条弧,容量为该申请的费用;从乙公司的每一条申请向t连一条弧,容量为每条申请对应的费用;然后对于甲公司的每一条申请,向所有与它矛盾的申请(只可能是乙公司的申请)连一条弧,容量为无穷大。那么,最小割便是这个最小代价,用申请费用总和减去最小代价便是最大收益。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<cmath>
# include<string>
# include<vector>
# include<list>
# include<set>
# include<map>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;

# define LL long long
# define REP(i,s,n) for(int i=s;i<n;++i)
# define CL(a,b) memset(a,b,sizeof(a))
# define CLL(a,b,n) fill(a,a+n,b)

const double inf=1e30;
const int INF=1<<30;
const int N=6005;

/////////////////////////////////
struct Edge
{
    int fr,to,cap,fw;
    Edge(int _fr,int _to,int _cap,int _fw):fr(_fr),to(_to),cap(_cap),fw(_fw){}
};
struct Dinic{
    vector<Edge>edges;
    vector<int>G[N];
    int d[N],vis[N],cur[N];
    int s,t;

    void init(int n,int s,int t)
    {
        this->s=0,this->t=t;
        REP(i,0,n) G[i].clear();
        edges.size();
    }

    void addEdge(int u,int v,int cap)
    {
        edges.push_back(Edge(u,v,cap,0));
        edges.push_back(Edge(v,u,0,0));
        int len=edges.size();
        G[u].push_back(len-2);
        G[v].push_back(len-1);
    }

    bool BFS()
    {
        CL(vis,0);
        d[s]=0;
        vis[s]=1;
        queue<int>q;
        q.push(s);
        while(!q.empty()){
            int x=q.front();
            q.pop();
            REP(i,0,G[x].size()){
                Edge &e=edges[G[x][i]];
                if(!vis[e.to]&&e.cap>e.fw){
                    d[e.to]=d[x]+1;
                    vis[e.to]=1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x,int a)
    {
        if(x==t||a==0) return a;
        int flow=0,f;
        for(int &i=cur[x];i<G[x].size();++i){
            Edge &e=edges[G[x][i]];
            if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.cap-e.fw)))>0){
                e.fw+=f;
                edges[G[x][i]^1].fw-=f;
                flow+=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }

    int MaxFlow()
    {
        int flow=0;
        while(BFS()){
            CL(cur,0);
            flow+=DFS(s,INF);
        }
        return flow;
    }
};
Dinic dinic;
////////////////////////////////////

int sum,maxn;
int a[300005],b[300005];
bool vis[3005][3005];
int p1[3005],p2[3005];

void init()
{
    maxn=sum=0;
    CL(a,0);
    CL(b,0);
}

bool read(int &x)
{
    x=0;
    char c;
    while(c=getchar()){
        if(c=='\n') return false;
        if(c==' ') return true;
        x=x*10+c-'0';
    }
}

int main()
{
    int T,n,m,cas=0;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d",&n);
        REP(i,1,n+1){
            scanf("%d",&p1[i]);
            sum+=p1[i];
            int x;
            getchar();
            while(read(x))
            {
                a[x]=i;
                maxn=max(maxn,x);
            }
            a[x]=i;
            maxn=max(maxn,x);
        }
        scanf("%d",&m);
        dinic.s=0,dinic.t=n+m+1;
        REP(i,1,m+1){
            scanf("%d",&p2[i]);
            sum+=p2[i];
            int x;
            while(read(x))
            {
                b[x]=i;
                maxn=max(maxn,x);
            }
            b[x]=i;
            maxn=max(maxn,x);
        }
        dinic.init(n+m+2,0,n+m+1);
        REP(i,1,n+1) dinic.addEdge(0,i,p1[i]);
        REP(i,1,m+1) dinic.addEdge(i+n,n+m+1,p2[i]);
        CL(vis,false);
        REP(i,1,maxn+1){
            if(!a[i]||!b[i]||vis[a[i]][b[i]]) continue;
            vis[a[i]][b[i]]=true;
            dinic.addEdge(a[i],b[i]+n,INF);
        }
        printf("Case %d:\n",++cas);
        printf("%d\n",sum-dinic.MaxFlow());
        if(T) printf("\n");
    }
    return 0;
}

  

posted @ 2015-12-23 14:16  20143605  阅读(385)  评论(0编辑  收藏  举报