最大权闭合图小结

来源:互联网 发布:汽车网站模板源码 编辑:程序博客网 时间:2024/05/22 01:42

最大权闭合图

昨天在做多校联赛的时候偶然碰上的,学习了下这个,首先推荐胡伯涛的《最小割模型在信息学竞赛中的应用》。

定义

一个有向图 的闭合图(closure)G=(V,E)是该有向图的一个点集,且该点集的所有出边都还指向该点集。即闭合图内的任意点的任意后继也一定在闭合图中。更形式化地说,闭合图是这样的一个点集VV ,满足对于 uV引出的 u,vE。那么给每个点v分配一个点权Wv(任意实数,可正可负)。大权闭合图(maximum weight closure),是一个点权之和大的闭合图,即大化vVWv

那么,我们的做法就是当Wv是负的时候,建一条边v,t容量为Wv,当Wv是正的时候,建一条边s,v容量为Wv,然后对于原来的边u,v保持不变,建一条u,v容量为inf的边。那么易证这个图的在最小割的情况下,和s相联通的子图是最大权闭合子图。
所以我们做法就是跑一次最大流,然后最大权闭合图的权值就是总收益-最大流。

POJ2987

这是一个非常裸地最大权闭合图,当Wv是负的时候,建一条边v,t容量为Wv,当Wv是正的时候,建一条边s,v容量为Wv,然后对于原来的边u,v保持不变,建一条u,v容量为inf的边。
然后直接按照原理跑一下最大流就好。

#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <set>#include <queue>#include <map>#include <cmath>#include <vector>using namespace std;#define N 5010#define pi acos(-1.0)#define inf 0x3f3f3f3f#define pb(x) push_back((x))typedef long long ll;typedef unsigned long long ull;struct edge{    int to,c,rev;};vector<edge> g[N];ll sum;int level[N],iter[N];int n,m;void addnode(int a,int b,int c){    g[a].push_back((edge){b,c,g[b].size()});    g[b].push_back((edge){a,0,g[a].size()-1});}void build_graph(int s,int t,int n,int m){    int tmp,u,v;    for(int i=1;i<=n;i++){        scanf("%d",&tmp);        if(tmp>=0){            addnode(s,i,tmp);            sum+=tmp;        }        else addnode(i,t,-tmp);    }    for(int i=1;i<=m;i++){        scanf("%d%d",&u,&v);        addnode(u,v,inf);    }}bool bfs(int s,int t){    memset(level,-1,sizeof(iter));    queue <int> q;    level[s]=0;    q.push(s);    while(!q.empty()){        int u=q.front();        q.pop();        for(int i=0;i<g[u].size();i++){            edge e=g[u][i];            if(e.c>0&&level[e.to]==-1){                level[e.to]=level[u]+1;                q.push(e.to);            }        }    }    if(level[t]==-1)return false;    return true;}int dfs(int u,int t,int f){    if(u==t) return f;    for(int &i=iter[u];i<g[u].size();i++){        edge &e=g[u][i];        if(e.c>0&&level[e.to]>level[u]){            int d=dfs(e.to,t,min(e.c,f));            if(d>0){                e.c-=d;                g[e.to][e.rev].c+=d;                return d;            }        }    }    return 0;}int main(){    int n,m;    while(~scanf("%d%d",&n,&m)){        sum=0;        build_graph(0,n+1,n,m);        ll ans=0;        while(bfs(0,n+1)){            memset(iter,0,sizeof(iter));            int f;            while((f=dfs(0,n+1,inf))>0){                ans+=f;            }        }        bfs(0,n+1);        int fire=0;        for(int i=1;i<=n;i++) if(level[i]>0) fire++;        printf("%d %lld\n",fire,sum-ans);        for(int i=0;i<=n+1;i++) g[i].clear();    }    return 0;}

HDU4971

水题。

#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <set>#include <queue>#include <map>#include <cmath>#include <vector>using namespace std;#define N 110#define pi acos(-1.0)#define inf 0x3f3f3f3f#define pb(x) push_back((x))typedef long long ll;typedef unsigned long long ull;struct edge{    int to,c,rev;};vector<edge> g[N];ll sum;int level[N],iter[N];int n,m;void addnode(int a,int b,int c){    g[a].push_back((edge){b,c,g[b].size()});    g[b].push_back((edge){a,0,g[a].size()});}void build_graph(int s,int t,int n,int m){    int tmp,u,v,k;    for(int i=1;i<=n;i++){        scanf("%d",&tmp);        addnode(s,i,tmp);        sum+=tmp;    }    for(int i=1;i<=m;i++){        scanf("%d",&tmp);        addnode(i+n,t,tmp);    }    for(int i=1;i<=n;i++){        scanf("%d",&k);        for(int j=1;j<=k;j++){            scanf("%d",&tmp);            addnode(i,n+tmp+1,inf);        }    }    for(int i=1;i<=m;i++){        for(int j=1;j<=m;j++){            scanf("%d",&tmp);            if(tmp) addnode(n+i,n+j,inf);        }    }}bool bfs(int s,int t){    memset(level,-1,sizeof(iter));    queue <int> q;    level[s]=0;    q.push(s);    while(!q.empty()){        int u=q.front();        q.pop();        for(int i=0;i<g[u].size();i++){            edge e=g[u][i];            if(e.c>0&&level[e.to]==-1){                level[e.to]=level[u]+1;                q.push(e.to);            }        }    }    if(level[t]==-1)return false;    return true;}int dfs(int u,int t,int f){    if(u==t) return f;    for(int &i=iter[u];i<g[u].size();i++){        edge &e=g[u][i];        if(e.c>0&&level[e.to]>level[u]){            int d=dfs(e.to,t,min(e.c,f));            if(d>0){                e.c-=d;                g[e.to][e.rev].c+=d;                return d;            }        }    }    return 0;}int main(){    int n,m,t,cnt=0;    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&m);        sum=0;        build_graph(0,n+m+1,n,m);        ll ans=0;        while(bfs(0,n+m+1)){            memset(iter,0,sizeof(iter));            int f;            while((f=dfs(0,n+1+m,inf))>0){                ans+=f;            }        }        printf("Case #%d: %d\n",++cnt,sum-ans);        for(int i=0;i<=n+m+1;i++) g[i].clear();    }    return 0;}

HDU5855

首先膜拜一下朝鲜队的出题大哥,题目质量太好了。
这道题我们直接二分最短的时间,然后对于每一次时间判断一下最大权闭合图是不是大于L就好

#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <set>#include <queue>#include <map>#include <cmath>#include <vector>using namespace std;#define N 410#define pi acos(-1.0)#define inf 0x3f3f3f3f#define pb(x) push_back((x))typedef long long ll;typedef unsigned long long ull;struct edge{    int to,c,rev;};vector<int> shop[N];vector<edge> g[N];int level[N];int iter[N];int n,m,L,tmp1,tmp2;int pt[N],pay[N],pro[N];int sum;inline void addnode(int a,int b,int c){    g[a].push_back((edge){b,c,g[b].size()});    g[b].push_back((edge){a,0,g[a].size()-1});}inline void build_graph(int mid){//建图    for(int i=1;i<=m;i++){        bool f=true;        addnode(0,i,pro[i]);        for(int j=0;j<shop[i].size();j++){            addnode(i,m+shop[i][j],inf);        }    }    for(int i=1;i<=n;i++){        if(pt[i]>mid) addnode(m+i,n+m+1,inf);        else addnode(m+i,n+m+1,pay[i]);    }}inline bool bfs(int s,int t){    memset(level,-1,sizeof(level));    queue <int> q;    level[s]=0;    q.push(s);    while(!q.empty()){        int u=q.front();        q.pop();        for(int i=0;i<g[u].size();i++){            edge &e=g[u][i];            if(e.c>0&&level[e.to]<0){                level[e.to]=level[u]+1;                q.push(e.to);            }        }    }    if(level[t]==-1) return false;    return true;}inline int dfs(int u,int t,int f){    if(u==t) return f;    for(int &i=iter[u];i<g[u].size();i++){        edge &e=g[u][i];        if(e.c>0&&level[e.to]>level[u]){            int d=dfs(e.to,t,min(f,e.c));            if(d>0){                e.c-=d;                g[e.to][e.rev].c+=d;                return d;            }        }    }    return 0;}inline int dinic(int mid){    int ans=0;    build_graph(mid);    while(bfs(0,n+m+1)){        memset(iter,0,sizeof(iter));        int f;        while((f=dfs(0,n+m+1,inf))>0){            ans+=f;        }//循环增广    }    for(int i=0;i<=n+m+1;i++) g[i].clear();    if(ans==0) return 0;    //printf("ans=%d %d\n",ans,sum-ans);    return sum-ans;}int main(){    int t;    int maxpt;    int cnt=0;    scanf("%d",&t);    while(t--){        scanf("%d%d%d",&n,&m,&L);        int maxpt=0;        sum=0;        for(int i=1;i<=n;i++){            scanf("%d%d",&pay[i],&pt[i]);            maxpt=max(pt[i],maxpt);        }        for(int i=1;i<=m;i++){            scanf("%d",&pro[i]);            sum+=pro[i];            scanf("%d",&tmp1);            for(int j=1;j<=tmp1;j++){                scanf("%d",&tmp2);                shop[i].push_back(tmp2);            }        }        int r=maxpt+1,l=0;        tmp1=0;        while(l<r){            //printf("%d %d ",l,r);            int mid=(l+r)/2;            if(l+1==r){                tmp1=dinic(r);                //printf("tmp1= %d\n",tmp1);                if(tmp1>=L){                    int ptmp1=dinic(l);                    //printf("tmp1= %d\n",ptmp1);                    if(ptmp1>=L) tmp1=ptmp1;                    else l=r;                }                else l=r+1;                break;            }            tmp1=dinic(mid);            if(tmp1>=L) r=mid;            else l=mid;            //printf("end= %d\n",tmp1);        }        printf("Case #%d: ",++cnt);        if(l<=maxpt){            printf("%d %d\n",l,tmp1);        }        else printf("impossible\n");        for(int i=1;i<=m;i++) shop[i].clear();    }    return 0;}
0 0
原创粉丝点击