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

来源:互联网 发布:华为大数据案例分析 编辑:程序博客网 时间:2024/05/01 15:24

题型:网络流


题意:

       有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;}/**1233 510 10 101 2 3 4 52 2 33 1 2 35 0 1 2 3 40 1 0 0 00 0 1 0 00 0 0 1 00 1 0 0 10 0 0 0 0122 310 108 10 61 01 20 1 00 0 00 0 010010 2060 65 10 48 31 14 14 4 92 305 7 6 43 24 10 30 40 5 3 28 31 43 25 42 16 43 45 27 302 1 116 11 6 2 3 17 1515 6 4 13 16 7 8 10 2 3 1 11 17 0 18 52 4 817 11 14 18 7 0 10 12 17 8 9 2 16 3 15 1 6 48 10 12 16 6 2 19 3 137 3 17 18 12 15 2 163 0 3 82 4 82 9 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 1 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 01 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 01 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 01 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 00 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 00 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 00 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0*/


0 0
原创粉丝点击