USC oj 1611 XX‘s dream

来源:互联网 发布:淘宝无线访客来源 编辑:程序博客网 时间:2024/06/01 13:29

最大权闭合子图介绍:

题目链接:
http://61.187.179.71:9988/problem.php?id=1611

题目大意:XX有很多梦想,完成梦想能获得价值X,但是一个梦想需要许多种努力,每种努力可能需要消耗价值也可能得到价值,问在获得最大价值的条件下,最多可完成多少种梦想

解题思路:

最大权闭合子图模板题,梦想和源点连边,可得到价值的努力也和源点连边,会消耗价值的努力和汇点连边,跑一遍网络流得到最小割,用所有正价值的和减去最小割即可。

但是这道题还要求最多能完成多少个梦想,一般情况下可能有多种不同的割边方式能得到我们需求的最大价值,所以我们求得的不一定是最大的。

这里有一个神奇的边权放大法,将所有与源点汇点相连的边乘以一个较大的常数(至少要大于图中梦想的点数),然后再给所有的梦想与源点相连的边的权值加1,这样最后得到的最大价值再除以我们乘的常数就是我们需求的价值,最多的梦想就是源点可以到达的梦想个数,直接在残余网络中dfs一遍统计能到达的梦想点就可以了(能到达的点就是我们建的边和反向边中权值大于0的)。

伪AC代码:
//oj上数据有问题。。(别问我为什么知道,标称都跑不过去,标称跑的结果和我一样。。。)

#include <iostream>#include <cstdio>#include <vector>#include <algorithm>#include <cstdlib>#include <stack>#include <map>#include <cstring>#include <string>#include <queue>typedef long long LL;const LL INF=1e15;using namespace std;const LL MAX_V=2100;struct edge{    LL to,cap,rev;    edge(LL a,LL b,LL c)    {        to = a;        cap =b;        rev = c;    }};vector<edge> g[MAX_V];LL level[MAX_V];LL iter[MAX_V];bool used[MAX_V];void add_edge(LL from,LL to,LL cap ){    //cout<<from<<"--¡·"<<to<< " "<<cap<<endl;    g[from].push_back(edge(to,cap,g[to].size()));    g[to].push_back(edge(from,0,g[from].size()-1));}void bfs(LL s){    memset(level,-1,sizeof(level));    queue<LL> que;    level[s]=0;    que.push(s);    while(!que.empty())    {        LL v=que.front();        que.pop();        for(LL i=0; i<g[v].size(); i++)        {            edge &e=g[v][i];            if(e.cap>0&&level[e.to]<0)            {                level[e.to]=level[v]+1;                que.push(e.to);            }        }    }}LL dfs(LL v,LL t,LL f){    if(v==t) return f;    for(LL &i=iter[v]; i<g[v].size(); i++)    {        edge &e = g[v][i];        if(e.cap >0&&level[v]<level[e.to])        {            LL d = dfs(e.to,t,min(f,e.cap));            if(d>0)            {                e.cap-=d;                g[e.to][e.rev].cap +=d;                return d;            }        }    }    return 0;}LL max_flow(LL s,LL t){    LL flow =0;    for(;;)    {        bfs(s);        if(level[t]<0) return flow;        memset(iter,0,sizeof(iter));        LL f;        while((f=dfs(s,t,INF))>0) flow+=f;    }}bool vis[MAX_V];void dfs1(LL v){    vis[v]=true;    for(LL i=0; i<g[v].size(); i++)    {        if(g[v][i].cap>0&&(!vis[g[v][i].to])) {                //cout<<v<<"-->"<<g[v][i].to<<endl;               // cout<<"cap = "<<g[v][i].cap<<endl;                dfs1(g[v][i].to);        }    }}int main(){    //cout<<INF<<endl;    LL m,n;    while(scanf("%I64d %I64d",&n,&m)!=EOF)    {        for(LL i=0; i<MAX_V; i++)            g[i].clear();        LL total=0;        for(LL i=1; i<=n; i++)        {            LL dream;            scanf("%I64d",&dream);            add_edge(0,i,dream*10000+1);            total+=dream*10000+1;        }        for(LL i=1; i<=m; i++)        {            LL tr;            scanf("%I64d",&tr);            if(tr>=0)            {                add_edge(0,n+i,tr*10000);                total+=tr*10000;            }            else add_edge(n+i,n+m+1,(-tr)*10000);        }        LL k;        for(LL i=1; i<=n; i++)        {            scanf("%I64d",&k);            for(LL j=1; j<=k; j++)            {                LL t;                scanf("%I64d",&t);                add_edge(i,n+t,INF);            }        }        LL ans2=0;        LL ans =(total- max_flow(0,n+m+1))/10000;        //cout<<"qq"<<endl;        memset(vis,0,sizeof(vis));        dfs1(0);        for(LL i=1;i<=n;i++)            if(vis[i]) ans2++;        printf("%I64d %I64d\n",ans,ans2);    }    return 0;}
0 0
原创粉丝点击