【CSU - 1319】 CX‘s dreams 【最大权闭合图 -- 最大化正点权个数】

版权声明:将来的你一定会感谢现在努力的你!!!! https://blog.csdn.net/qq_37383726/article/details/79965931

CX有很多的梦想,但是没有付出拿来的收获。比如CX想拥有巧克力般的八块腹肌,就要在健身房举哑铃以及跑步,这是很累的。比如CX要成为ACM大犇,就要刷题1000道,但CX是很享受刷题的,所以并不一定所有的付出都会让CX感到很累、不喜欢。于是CX对每个梦想和每个付出进行了估值,每个梦想有其权值(非负数),代表实现这个梦想能收获的权值,而每个梦想可能需要多个付出来满足,并且一个付出不一定只对应一个梦想,梦想能够实现只有其所需的付出都完成了才行。对于每个付出,也有一个权值(可正可负),代表CX完成这个付出能得到的权值(越小代表CX越不喜欢这个付出,所以负数代表CX有多讨厌该付出,正数代表CX有多喜欢这个付出,为0代表说不上喜欢还是不喜欢)。CX是一个享受生活的人,希望得到的权值最多(完成付出得到的权值+实现梦想得到的权值),当有多个方式可以使权值最多时,希望能完成的梦想最多。现在给出每个梦想、付出的权值,以及梦想和付出的关系,请你求出CX能获得的最大权值,以及在这个条件下的能够实现的最多梦想数目。

Input
多组数据输入(最多20组),输入读到文件结束。

每组数据第一行两个整数N,M。其中N代表CX有N(1<=N<=1000)个梦想可选则,M代表有M(1<=M<=1000)个付出可选择。

接下来一行N个数,第i个数Ri(0<=wi<=10^5)代表第i个梦想实现了可以获得的权值。

接下来一行M个数,第i个数Ci(-10^5<=Ci<=10^5)代表第i个付出的权值(正数代表完成该付出可以获得权值,负数代表完成该付出会去掉权值)。

接下来N行,描述每个梦想所需要的付出,第一个数K(K<=min(50,M))代表该梦想所需要的付出数量,接下K个数,第i个数Pi代表其所需要的第i个付出为Pi(1<=Pi<=M)。

Output
每组输入对应一行输出,输出两个整数A B。

A代表所能获得的最大权值,B代表能获得这么多权值下所能完成的最多梦想。

Sample Input
3 3
5 6 7
1 -10 -5
1 3
2 1 3
3 1 2 3
Sample Output
7 2
Hint
CSU_ZZY

分析: 首先对于正点权的付出,因为其没有后继,所以最小割肯定不会割这个边,所以我们可以直接取而不用建边 。 然后剩下的图,我们就可以将它看做一个裸的最大权闭合图模型了。
最大的权值很好处理。 关键就是那个最大化梦想个数,这个怎么处理呢?
这个处理的方法好巧妙,Otz 。

先看一下 建图方法,然后再讨论分析: 设一个整数 C
S —-> 正点权的梦想 , cap为 C*dreamval +1
负点权的付出—->T ,cap为 C *workval
对于梦想和付出的关系部分边 还是一样的为INF
假设这样跑下来的最小割为F

分析一下:因为要求的是S-T的最小割,而且割边都是简单割,所以如果有一种情况 割梦想的点权和割付出的点权一样大(没有上面的+1部分,确实会有这种情况),割哪个都可以,但是这里我们加了1,这样的话肯定会优先割付出的边。 这样不就正好是最大化梦想个数了吗?

什么? 你说为什么不直接+1,还乘C干嘛 ?其实是为了将C当成一种变相的模。如果我们乘了C,不+1的话,最后是不是肯定是C的倍数的流 F=k*C? 当然这样也没有什么意义,但是如果我们再加上1,这样的话,我们就会发现 ,最后肯定会多一些 流,而这些流 思考一下就会发现 它就是割的梦想个数(可以用F%C得到)。而最后的 真正的最小割权值应该为F/C (整数除法) .[ 从分析中,我们也可以发现C的大小一定要是 大于总梦想的个数,因为最后F最多多n个流,而我们同时要将其取模取出来]

代码

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>

using namespace std;
#define LL long long

const int  N = 2e3+11;
const int M = 1e5+11;
const LL inf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const LL C   = 1e5;

struct Edge {
    int form,to,nexts;
    LL cap,flow;
    Edge(){}
    Edge (int _form,int _to,LL _cap,LL _flow,int _nexts){
        form=_form; to=_to; cap=_cap; flow=_flow; nexts=_nexts;
    }
}edge[M];
int head[N],top;
void init(){
    memset(head,-1,sizeof(head));
    top=0;
}
void addedge(int a,int b,LL c){
    edge[top]=Edge(a,b,c,0,head[a]); head[a]=top++;
    edge[top]=Edge(b,a,0,0,head[b]); head[b]=top++;
}

int vis[N],dis[N];
int cur[N];
bool bfs(int st,int ed){
    queue<int>Q;
    memset(vis,0,sizeof(vis));
    memset(dis,-1,sizeof(dis));
    Q.push(st);vis[st]=1;dis[st]=1;
    while(!Q.empty()){
        int now=Q.front();Q.pop();
        for(int i=head[now];i!=-1;i=edge[i].nexts){
            Edge e=edge[i];
            if(!vis[e.to]&&e.cap-e.flow>0){
                vis[e.to]=1;
                dis[e.to]=dis[now]+1;
                if(e.to==ed) return 1;
                Q.push(e.to);
            }
        }
    }
    return 0;
}
LL dfs(int now,LL a,int ed){
    if(a==0||now==ed) return a;
    LL flow=0,f;
    for(int &i=cur[now];i!=-1;i=edge[i].nexts){
        Edge &e=edge[i];
        if(dis[e.to]==dis[now]+1&&(f=dfs(e.to,min(e.cap*1ll-e.flow,a),ed))>0){
            e.flow+=f;
            flow+=f;
            edge[i^1].flow-=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}
LL max_flow(int st ,int ed){
    LL flow=0;
    while(bfs(st,ed)){
        memcpy(cur,head,sizeof(head));
        flow+=dfs(st,inf,ed);
    }
    return flow;
}
int work[N];
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        int S=0,T=n+m+1; LL ans=0;
        for(int i=1;i<=n;i++){
            LL z;scanf("%lld",&z);
            addedge(S,i,z*C+1);
            ans+=z;
        }

        for(int i=1;i<=m;i++){
            LL z;scanf("%lld",&work[i]);
            z=work[i];
            if(z>=0) ans+=z;
            else addedge(n+i,T,-z*C);
        }

        for(int i=1;i<=n;i++){
            int k;scanf("%d",&k);
            for(int j=1;j<=k;j++){
                LL z;scanf("%lld",&z);
                if(work[z]>=0) continue;
                addedge(i,n+z,inf);
            }
        }

        LL mx=max_flow(S,T);
        LL ge=mx%C;
        ans-=mx/C;
        printf("%lld %lld\n",ans,n-ge);
    }
return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页