zoukankan      html  css  js  c++  java
  • HDU 4971

    有n(20)个工程,完成每个工程获得收益是p[i],m(50)个需要解决的难题,解决每个难题花费是c[i]

    要完成第i个工程,需要先解决ki个问题,具体哪些问题,输入会给出

    每个难题之间可能有依赖关系,比如i->j就是解决问题j需要实现解决问题i。(题目描述有问题,但是按照样例来看,是前后说反了,也就是按照题意这个地方反向建图就可以)

    问,最大收益可以是多少

    比较裸的最大权闭合图,解决最大权闭合图一般用最大流的方法

    然而训练的时候并不知道这个,所以结束后看了看相关的资料,

    下面仅说明一下建图方法。

    建立一个源点S,s向每个工程点连一条边,权值是p[i],

    建立一个汇点T,t向每个问题连一条边,权值是c[i]

    接着,工程与完成工程需要的解决的问题,连一条边,权值INF

    难题之间按照题目连边,权值仍为INF

    求出最大流maxflow

    答案就是sigema(p[i])-maxflow

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<string>
    #include<sstream>
    #define eps 1e-9
    #define ALL(x) x.begin(),x.end()
    #define INS(x) inserter(x,x.begin())
    #define FOR(i,j,k) for(int i=j;i<=k;i++)
    #define MAXN 1005
    #define MAXM 40005
    #define INF 0x3fffffff
    #define PB push_back
    #define MP make_pair
    #define X first
    #define Y second
    #define lc (k<<1)
    #define rc ((k<<1)1)
    #define V(x) vector<x >
    #define vs V(string)
    #define vi V(int)
    #define fr(x,y,z) for ((x)=(y);(x)<(z);(x)++)
    #define fo(x,y) fr(x,0,y)
    #define fir(n) fo(i,n)
    #define fjr(n) fo(j,n)
    #define fkr(n) fo(k,n)
    #define fi fir(n)
    #define fj fjr(n)
    #define fk fkr(n)
    #define pb push_back
    #define sz size()
    #define cs c_str()
    #define clr(x,y) memset((x),(y),sizeof(x))
    #define df double
    using namespace std;
    typedef long long LL;
    int i,j,k,n,m,x,y,T,ans,big,cas,num,len;
    bool flag;
    
    const int inf = 0x3f3f3f3f;
    struct edgenode
    {
        int from,to,next;
        int cap;
    }edge[MAXM];
    int Edge,head[MAXN],ps[MAXN],dep[MAXN];
    
    void add_edge(int x,int y,int c)
    {
        edge[Edge].from=x;
        edge[Edge].to=y;
        edge[Edge].cap=c;
        edge[Edge].next=head[x];
        head[x]=Edge++;
        
        edge[Edge].from=y;
        edge[Edge].to=x;
        edge[Edge].cap=0;
        edge[Edge].next=head[y];
        head[y]=Edge++;
    }
    
    int dinic(int n,int s,int t)
    {
        int tr,flow=0;
        int i,j,k,l,r,top;
        while(1){
            memset(dep,-1,(n+1)*sizeof(int));
            for(l=dep[ps[0]=s]=0,r=1;l!=r;)//BFS部分,将给定图分层 
            {
                for(i=ps[l++],j=head[i];j!=-1;j=edge[j].next)
                {
                    if (edge[j].cap&&-1==dep[k=edge[j].to])
                    {
                        dep[k]=dep[i]+1;ps[r++]=k;
                        if(k==t)
                        {
                            l=r;
                            break;
                        }
                    }
                }
            }
            if(dep[t]==-1)break;
            
            for(i=s,top=0;;)//DFS部分 
            {
                if(i==t)//当前点就是汇点时 
                {
                    for(k=0,tr=inf;k<top;++k)
                        if(edge[ps[k]].cap<tr)tr=edge[ps[l=k]].cap;
                        
                    for(k=0;k<top;++k)
                        edge[ps[k]].cap-=tr,edge[ps[k]^1].cap+=tr;
                        
                    flow+=tr;
                    i=edge[ps[top=l]].from;
                }
                
                for(j=head[i];j!=-1;j=edge[j].next)//找当前点所指向的点 
                    if(edge[j].cap&&dep[i]+1==dep[edge[j].to]) break;
                    
                if(j!=-1)
                {
                    ps[top++]=j;//当前点有所指向的点,把这个点加入栈中 
                    i=edge[j].to;
                }
                else
                { 
                    if (!top) break;//当前点没有指向的点,回溯 
                    dep[i]=-1;
                    i=edge[ps[--top]].from;
                }
            }
        }
        return flow;
    }
    
    int p[MAXN],c[MAXN],t;
    
    int main()
    {
        scanf("%d",&T);
        while (T--)
        {
            memset(head,-1,sizeof(head));
            Edge=0;
            scanf("%d%d",&n,&m);
            int sum=0;
            for (i=0;i<n;i++)
            {
                scanf("%d",&p[i]);
                add_edge(0,i+1,p[i]);
                sum+=p[i];
            }
            for (i=0;i<m;i++) 
            {
                scanf("%d",&c[i]);
                add_edge(n+1+i,n+m+1,c[i]);
            }
            for (i=0;i<n;i++)
            {
                scanf("%d",&k);
                //E[i].clear();
                for (j=0;j<k;j++)
                {
                    scanf("%d",&t);
                    add_edge(i+1,t+n+1,INF);
                    //E[i].PB(t);
                }
            }
            
            for (i=0;i<m;i++)
            {
                for (j=0;j<m;j++)
                {
                    scanf("%d",&t);
                    if (t)
                    {
                        add_edge(i+1+n,j+1+n,INF);
                    }
                }
            }
            
            printf("Case #%d: %d
    ",++cas,sum-dinic(m+n+2,0,n+m+1));
            
        }
        return 0;
    }
  • 相关阅读:
    Golang 函数
    Golang type
    Golang 分支控制和循环
    Golang 字符型
    Golang运算符
    final 和 static 的区别
    Golang标识符命名规则
    Golang值类型与引用类型
    Golang指针
    启动 jvm 参数小总结
  • 原文地址:https://www.cnblogs.com/zhyfzy/p/4557560.html
Copyright © 2011-2022 走看看