HDU_4971_A simple brute force problem.(最大权闭合图)

题型:网络流


题意:

       有n个项目,m个技术问题。做项目会挣钱,解决技术问题需要花钱。想要完成一个项目,就要解决对应的技术问题,求能获得的最多的利润。


分析:

      赤果果的最大权闭合图问题。

      先学习一下闭合图的概念。

      闭合图就是,对于一个点集V,如果他们的所有的边所指向的点都在点集V中,则这个点集加上他们的边是闭合图。

如图:


        1、2、4、5组成的图就是闭合图,3、4、5组成的图也是闭合图,而1、2、5组成的图就不是闭合图,因为点1有一条边连出去了。

       每个点有权值正负零都有可能,选某个点u,如果必须选v,则我们设u,v有一条有向边。最后要我们有一种选取方案使得所选的点权值和最大。这就是最大权闭合图。
       解法用最大流来解。


       建图方法是:s源点到所有正权点连流量为那个点权值的边,所有负权点到汇点t连流量为负权绝对值的边。原来图中的依赖关系正常建边,流量定为inf。
       跑出来的最大流就是最小割。用所有正权的和减去最小割就是可获得的最大权。

 证明:

        因为中间的都是inf,所以最小割肯定是割到与s连的或者与t连的边。那么就是我们选择一些正权或者负权,并且我们都是选小的。也就是说对于正权到s这里,如果正权很小,并且选他就必须选一些负权很大的边,那么我们在最小割中也会选这个正权小的,使得st不连通。反之,如果负权那里小,我们就会选择割负权。最后正权的总和减去最小割。


         对于本题,可以清楚的看出可以转化为最大权闭合图来求解:

                 首先由于技术问题的图可能形成环,所以需要先缩点,建成新的图,下面构造网络流的图。

                 源点S与每个项目建边,权值为项目的收入;

                 项目与所对应的技术问题建边,权值为inf;

                 技术问题与技术问题之间,有前驱关系的技术问题建边,例如i是j的前驱,则j->i,权值为inf;

                 每一个技术问题与汇点T建边,权值为技术问题的花费。

         最大利润等于完成所有项目的收入减去最大流。


代码:

一不小心突破本人单个文件代码长度上限,9000+B不解释~

#include<iostream>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdlib>
#include<algorithm>
#include<cstring>

#define mt(a,b) memset(a,b,sizeof(a))

using namespace std;
const int M = 123456;
const int inf = 0x7f7f7f7f;

int profit[30],cost[60];


class Tarjan { ///Tarjan 算法有向图强连通分量缩点
public:
    struct E {
        int u,v,next;
    } e[M<<4]; ///Bcnt 强连通分量的个数,num 个分量的点数,belong属于哪个分量
    int le,head[M],Index,Bcnt,num[M],belong[M],dfn[M],low[M];
    bool instack[M];
    stack<int> s;
    void tarjan(int u) {
        dfn[u]=low[u]=++Index;
        instack[u]=true;
        s.push(u);
        int v;
        for(int i=head[u]; ~i; i=e[i].next) {
            v=e[i].v;
            if(!dfn[v]) {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            } else if(instack[v]) {
                low[u]=min(low[u],dfn[v]);
            }
        }
        if(dfn[u]==low[u]) {
            Bcnt++;
            do {
                v=s.top();
                s.pop();
                instack[v]=false;
                belong[v]=Bcnt;
                num[Bcnt]++;
            } while(u!=v);
        }
    }
    void init() {
        le=Index=Bcnt=0;
        mt(head,-1);
        mt(num,0);
        mt(dfn,0);
        mt(low,0);
        mt(instack,0);
        while(!s.empty()) s.pop();
    }
    void add(int u,int v) {
        e[le].u=u;
        e[le].v=v;
        e[le].next=head[u];
        head[u]=le++;
    }
    void solve(int n) {
        for(int i=1; i<=n; i++) {
            if(!dfn[i]) {
                tarjan(i);
            }
        }
    }
    int getbcnt() {
        return Bcnt;
    }
    int getbelong(int id) {
        return belong[id];
    }
    int getnum(int id) {
        return num[id];
    }
} gx;


class Dinic { //最大流
    struct E {
        int u,v,next,flow;
    } e[M<<1];
    int le,flow,head[M],temp[M],cur[M],level[M],path[M];
    bool used[M];
    queue<int> q;
public:
    int getflow() {
        return flow;
    }
    bool bfs(int s,int t) {
        mt(level,-1);
        while(!q.empty()) q.pop();
        q.push(s);
        level[s]=1;
        while(!q.empty()) {
            int u=q.front();
            q.pop();
            for(int i=head[u]; ~i; i=e[i].next) {
                int v=e[i].v;
                if(level[v]==-1&&e[i].flow) {
                    level[v]=level[u]+1;
                    q.push(v);
                    if(v==t) return true;
                }
            }
        }
        return false;
    }
    void init() {
        le=0;
        mt(head,-1);
    }
    void add(int u,int v,int flow) {
        e[le].u=u;
        e[le].v=v;
        e[le].flow=flow;
        e[le].next=head[u];
        head[u]=le++;
        e[le].u=v;
        e[le].v=u;
        e[le].flow=0;
        e[le].next=head[v];
        head[v]=le++;
    }
    void solve(int s,int t) {
        int p,now,tempp;
        bool flag;
        flow=0;
        while(bfs(s,t)) {
            for(int i=0; i<M; i++) {
                temp[i]=head[i];
                used[i]=true;
            }
            p=1;
            path[p]=s;
            while(p) {
                int u=path[p];
                if(u==t) {
                    now=inf;
                    for(int i=1; i<p; i++) {
                        now=min(now,e[cur[path[i]]].flow);
                    }
                    flow+=now;
                    for(int i=1; i<p; i++) {
                        e[cur[path[i]]].flow-=now;
                        e[cur[path[i]]^1].flow+=now;
                        if(!e[cur[path[i]]].flow) tempp=i;
                    }
                    p=tempp;
                } else {
                    flag=false;
                    for(int i=temp[u]; ~i; i=e[i].next) {
                        int v=e[i].v;
                        if(used[v]&&e[i].flow&&level[u]+1==level[v]) {
                            cur[u]=i;
                            temp[u]=e[i].next;
                            flag=true;
                            path[++p]=v;
                            break;
                        }
                    }
                    if(flag) continue;
                    p--;
                    used[u]=false;
                }
            }
        }
    }
} ts;

struct project_problems {
    int num;
    int question[55];
} project[25];

int Map[55][55];
struct Node {
    int value;
} newgraph[55];

int main() {
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int _,cas = 0;
    int n,m;
    int allprofit;
    scanf("%d",&_);
    while(_--) {
        scanf("%d%d",&n,&m);
        allprofit = 0;
        for(int i=0; i<n; i++) {
            scanf("%d",&profit[i]);
            allprofit += profit[i];
        }
        for(int i=0; i<m; i++) {
            scanf("%d",&cost[i]);
        }
        ///网络流初始化
        ts.init();
        ///缩点初始化
        gx.init();

        ///输入项目的问题
        for(int i=0; i<n; i++) {
            int num;
            scanf("%d",&num);
            project[i].num = num;
            for(int j=0; j<num; j++) {
                scanf("%d",&project[i].question[j]);
            }
        }

        ///输入problems之间的关系
        int tmp;
        for(int i=0; i<m; i++) {
            for(int j=0; j<m; j++) {
                scanf("%d",&tmp);
                Map[i][j] = tmp;
                if(tmp == 1) {
                    gx.add(i+1,j+1);
                }
            }
        }

        ///缩点
        gx.solve(m);
//        printf("jihenum======%d\n",gx.getbcnt());

        ///建成新的图
        for(int i=0; i<=m; i++) {
            newgraph[i].value = 0;
        }
        for(int i=0; i<m; i++) {
            newgraph[gx.getbelong(i+1)].value += cost[i];
        }


//        puts("******************");
//        for(int i=1;i<=gx.getbcnt();i++){
//            printf("%d ",newgraph[i].value);
//        }
//        puts("");
//        puts("******************");

        ///网络流建图
        ///源点S为n+m+1
        ///汇点T为n+m+2
        int s = n+m+1;
        int t = n+m+2;
        ///S与project连接
        for(int i=0; i<n; i++) {
            ts.add(s,i,profit[i]);
        }
        ///project与problem建图
        for(int i=0; i<n; i++) {
            for(int j=0; j<project[i].num; j++) {
                project[i].question[j] = gx.getbelong(project[i].question[j]+1);
            }
            sort(project[i].question,project[i].question+project[i].num);
            project[i].num = unique(project[i].question,project[i].question+project[i].num) - project[i].question;
            for(int j=0; j<project[i].num; j++) {
                ts.add(i,project[i].question[j]+n,inf);
            }
        }

//        puts("**************************");
//        for(int i=0;i<n;i++){
//            for(int j=0;j<project[i].num;j++){
//                printf("%d ",project[i].question[j]);
//            }
//            puts("");
//        }
//        puts("**************************");
        bool flag[55][55];
        mt(flag,false);

        ///problem与problem建图
        for(int i=0; i<m; i++) {
            for(int j=0; j<m; j++) {
                if(gx.getbelong(i+1)!=gx.getbelong(j+1) && Map[i][j]==1 && !flag[gx.getbelong(i+1)][gx.getbelong(i+1)]) {
                    ts.add(gx.getbelong(i+1)+n,gx.getbelong(j+1)+n,inf);
                    flag[gx.getbelong(i+1)][gx.getbelong(j+1)] = true;
                }
            }
        }
        ///problem与T连接
        for(int i=1; i<=gx.getbcnt(); i++) {
//            printf("i=%d t cost  =%d\n",i,newgraph[i].value);
            ts.add(i+n,t,newgraph[i].value);
        }

        ///跑最大流
        ts.solve(s,t);

//        printf("flow = %d\n",ts.getflow());

        printf("Case #%d: %d\n",++cas,allprofit - ts.getflow());

    }

    return 0;
}
/**
123
3 5
10 10 10
1 2 3 4 5
2 2 3
3 1 2 3
5 0 1 2 3 4
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 1 0 0 1
0 0 0 0 0


12
2 3
10 10
8 10 6
1 0
1 2
0 1 0
0 0 0
0 0 0

100
10 20
60 65 10 48 31 14 14 4 92 30
5 7 6 43 24 10 30 40 5 3 28 31 43 25 42 16 43 45 27 30
2 1 11
6 11 6 2 3 17 15
15 6 4 13 16 7 8 10 2 3 1 11 17 0 18 5
2 4 8
17 11 14 18 7 0 10 12 17 8 9 2 16 3 15 1 6 4
8 10 12 16 6 2 19 3 13
7 3 17 18 12 15 2 16
3 0 3 8
2 4 8
2 9 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
电子书资源服务系统是一款基于 Java Swing 的 C-S 应用,旨在提供电子书资源一站式服务,可从系统提供的书资源中直接检索资源并进行下载。.zip优质项目,资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松copy复刻,拿到资料包后可轻松复现出一样的项目。 本人系统开发经验充足,有任何使用问题欢迎随时与我联系,我会及时为你解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(若有),项目具体内容可查看下方的资源详情。 【附带帮助】: 若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步。 【本人专注计算机领域】: 有任何使用问题欢迎随时与我联系,我会及时解答,第一时间为你提供帮助,CSDN博客端可私信,为你解惑,欢迎交。 【适合场景】: 相关项目设计中,皆可应用在项目开发、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面中 可借鉴此优质项目实现复刻,也可以基于此项目进行扩展来开发出更多功能 【无积分此资源可联系获取】 # 注意 1. 本资源仅用于开源学习和技术交。不可商用等,一切后果由使用者承担。 2. 部分字体以及插等来自网络,若是侵权请联系删除。积分/付费仅作为资源整理辛苦费用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值