zoukankan      html  css  js  c++  java
  • HDU4971 A simple brute force problem.(强连通分量缩点 + 最大权闭合子图)

    题目

    Source

    http://acm.hdu.edu.cn/showproblem.php?pid=4971

    Description

    There's a company with several projects to be done. Finish a project will get you profits. However, there are some technical problems for some specific projects. To solve the problem, the manager will train his employee which may cost his budget. There may be dependencies between technical problems, for example, A requires B means you need to solve problem B before solving problem A. If A requires B and B requires A, it means that you should solve them at the same time. You can select which problems to be solved and how to solve them freely before finish your projects. Can you tell me the maximum profit?

    Input

    The first line of the input is a single integer T(<=100) which is the number of test cases.

    Each test case contains a line with two integer n(<=20) and m(<=50) which is the number of project to select to complete and the number of technical problem.

    Then a line with n integers. The i-th integer(<=1000) means the profit of complete the i-th project.

    Then a line with m integers. The i-th integer(<=1000) means the cost of training to solve the i-th technical problem.

    Then n lines. Each line contains some integers. The first integer k is the number of technical problems, followed by k integers implying the technical problems need to solve for the i-th project.

    After that, there are m lines with each line contains m integers. If the i-th row of the j-th column is 1, it means that you need to solve the i-th problem before solve the j-th problem. Otherwise the i-th row of the j-th column is 0.

    Output

    For each test case, please output a line which is "Case #X: Y ", X means the number of the test case and Y means the the maximum profit.

    Sample Input

    4
    2 3
    10 10
    6 6 6
    2 0 1
    2 1 2
    0 1 0
    1 0 0
    0 0 0
    2 3
    10 10
    8 10 6
    1 0
    1 2
    0 1 0
    1 0 0
    0 0 0
    2 3
    10 10
    8 10 6
    1 0
    1 2
    0 1 0
    0 0 0
    0 0 0
    2 3
    10 10
    8 10 6
    1 0
    1 2
    0 0 0
    1 0 0
    0 0 0

    Sample Output

    Case #1: 2
    Case #2: 4
    Case #3: 4
    Case #4: 6

    分析

    题目大概说有n个可以获益的项目,还有m个有一定代价的技术问题。解决某个项目需要先解决某些技术问题;而解决某些技术问题又需要解决另外一些技术问题;如果两个技术问题互相依赖,则要同时解决它们。问能获得的最少收益是多少。

    m个技术问题看成点,依赖关系看成边,然后求强连通分量并缩点形成DAG,这样就是最大权闭合子图问题了,最小割解决即可。

    代码

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define INF (1<<30)
    #define MAXN 111
    #define MAXM 2222
     
    struct Edge{
        int v,cap,flow,next;
    }edge[MAXM];
    int vs,vt,NE,NV;
    int head[MAXN];
     
    void addEdge(int u,int v,int cap){
        edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0;
        edge[NE].next=head[u]; head[u]=NE++;
        edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0;
        edge[NE].next=head[v]; head[v]=NE++;
    }
     
    int level[MAXN];
    int gap[MAXN];
    void bfs(){
        memset(level,-1,sizeof(level));
        memset(gap,0,sizeof(gap));
        level[vt]=0;
        gap[level[vt]]++;
        queue<int> que;
        que.push(vt);
        while(!que.empty()){
            int u=que.front(); que.pop();
            for(int i=head[u]; i!=-1; i=edge[i].next){
                int v=edge[i].v;
                if(level[v]!=-1) continue;
                level[v]=level[u]+1;
                gap[level[v]]++;
                que.push(v);
            }
        }
    }
     
    int pre[MAXN];
    int cur[MAXN];
    int ISAP(){
        bfs();
        memset(pre,-1,sizeof(pre));
        memcpy(cur,head,sizeof(head));
        int u=pre[vs]=vs,flow=0,aug=INF;
        gap[0]=NV;
        while(level[vs]<NV){
            bool flag=false;
            for(int &i=cur[u]; i!=-1; i=edge[i].next){
                int v=edge[i].v;
                if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){
                    flag=true;
                    pre[v]=u;
                    u=v;
                    //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
                    aug=min(aug,edge[i].cap-edge[i].flow);
                    if(v==vt){
                        flow+=aug;
                        for(u=pre[v]; v!=vs; v=u,u=pre[u]){
                            edge[cur[u]].flow+=aug;
                            edge[cur[u]^1].flow-=aug;
                        }
                        //aug=-1;
                        aug=INF;
                    }
                    break;
                }
            }
            if(flag) continue;
            int minlevel=NV;
            for(int i=head[u]; i!=-1; i=edge[i].next){
                int v=edge[i].v;
                if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
                    minlevel=level[v];
                    cur[u]=i;
                }
            }
            if(--gap[level[u]]==0) break;
            level[u]=minlevel+1;
            gap[level[u]]++;
            u=pre[u];
        }
        return flow;
    }
    
    int n,m;
    
    int profit[22],cost[55];
    int need[22][55],G[55][55];
    
    int top,stack[MAXN];
    bool instack[MAXN];
    int dn,dfn[MAXN],low[MAXN];
    int bn,belong[MAXN];
    void tarjan(int u){
        dfn[u]=low[u]=++dn;
        stack[++top]=u; instack[u]=1;
        for(int v=1; v<=m; ++v){
            if(u==v || G[u][v]==0) continue;
            if(dfn[v]==0){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }else if(instack[v]){
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u]){
            int v; ++bn;
            do{
                v=stack[top--];
                instack[v]=0;
                belong[v]=bn;
            }while(u!=v);
        }
    }
    
    int main(){
    	int t;
    	scanf("%d",&t);
    	for(int cse=1; cse<=t; ++cse){
    		scanf("%d%d",&n,&m);
    		for(int i=1; i<=n; ++i){
    			scanf("%d",profit+i);
    		}
    		for(int i=1; i<=m; ++i){
    			scanf("%d",cost+i);
    		}
    		int a,b;
    		for(int i=1; i<=n; ++i){
    			need[i][0]=0;
    			scanf("%d",&a);
    			while(a--){
    				scanf("%d",&b);
    				need[i][++need[i][0]]=b+1;
    			}
    		}
    		for(int i=1; i<=m; ++i){
    			for(int j=1; j<=m; ++j){
    				scanf("%d",&G[i][j]);
    			}
    		}
    		
    		top=0; dn=0; bn=0;
    		memset(dfn,0,sizeof(dfn));
    		memset(instack,0,sizeof(instack));
    		for(int i=1; i<=m; ++i){
    			if(dfn[i]==0) tarjan(i);
    		}
    		vs=0; vt=n+bn+1; NV=vt+1; NE=0;
    		memset(head,-1,sizeof(head));
    		int tot=0;
    		for(int i=1; i<=n; ++i){
    			tot+=profit[i];
    			addEdge(vs,i,profit[i]);
    			for(int j=1; j<=need[i][0]; ++j){
    				addEdge(i,belong[need[i][j]]+n,INF);
    			}
    		}
    		for(int i=1; i<=bn; ++i){
    			int cnt=0;
    			for(int j=1; j<=m; ++j){
    				if(belong[j]==i) cnt+=cost[j];
    			}
    			addEdge(i+n,vt,cnt);
    		}
    		for(int i=1; i<=m; ++i){
    			for(int j=1; j<=m; ++j){
    				if(G[i][j]==0 || belong[i]==belong[j]) continue;
    				addEdge(belong[i]+n,belong[j]+n,INF);
    			}
    		}
    		printf("Case #%d: %d
    ",cse,tot-ISAP());
    	}
    	return 0;
    }
    
  • 相关阅读:
    开启ecstore隐藏的功能
    对接ECOS框架(含ecstore、ocs、erp等产品)的方法【其他系统请求ecos的api接口】
    shopex 网店系统基于云登录系统的信任登录设置
    怎样获取机器码
    windows 无法连接远程桌面
    ecos框架中data/ 目录下img*文件数量过多的问题
    mac 下brew解决php安装问题
    20140708 总结
    20140705 总结
    bzoj 2751
  • 原文地址:https://www.cnblogs.com/WABoss/p/5815039.html
Copyright © 2011-2022 走看看