其他分享
首页 > 其他分享> > Firing POJ - 2987 最大权闭合子图

Firing POJ - 2987 最大权闭合子图

作者:互联网

最大权闭合子图:一张图,一些点权值为正,一些点权值为负,选了一些点必须选择器后继节点,问权值最大的子图。

考虑最小割做法:

源点向点权为正的点连边,点权为负的点向汇点连边,其他点两两连边流量为inf,求最小割为答案。

设  点权为正的点与源点连边表示选择这个点

设  点权为负的点与源点连边表示不选择这个点

如果图联通:选择一个点又不选择后继节点,与闭合子图的定义矛盾,所以图必然不连通。

求一遍最小割:实际上是 不选择的点权为正的点+选择的点权为负的绝对值。保证最小。

那么:最大权闭合子图的权值为:正点权和-(不选择的点权为正的点+选择的点权为负的绝对值)

Firing

 POJ - 2987 
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+500;
typedef long long ll;
const ll INF=1e17;
int n,m,S,T;
struct Dinic{
    int head[N],dep[N];
    int ecnt,cnt; 
    int vis[N];
    struct edge{
        int v,next;ll flow;
    }e[N*10];

    void init(){
        memset(head, -1, sizeof head);
        ecnt = cnt=0;
        memset(vis,0,sizeof vis);
    }

    void addedge(int u, int v, ll flow) {
    e[ecnt].v=v;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++;
    e[ecnt].v=u;e[ecnt].flow=0;e[ecnt].next=head[v];head[v]=ecnt++;
    }

    bool BFS(){//分层图找增广路
        memset(dep,0,sizeof dep);
        queue<int>Q;
        Q.push(S);dep[S]=1;
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            for(int i=head[u];~i;i=e[i].next){
                if(e[i].flow&&!dep[e[i].v]){
                    dep[e[i].v]=dep[u]+1;
                    Q.push(e[i].v);
                }
            }
        }
        return dep[T];
    }
    void cut(int u){
        vis[u]=1;
        cnt++;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].v;
            if(e[i].flow&&!vis[v])cut(v);
        }
    }
    ll DFS(int u,ll f){//推进新流
        if(u==T||f==0)return f;
        ll w,used=0;
        for(int i=head[u];~i;i=e[i].next){
            if(e[i].flow&&dep[e[i].v]==dep[u]+1){
                w=DFS(e[i].v,min(f,e[i].flow));//多路增广
                e[i].flow-=w;e[i^1].flow+=w;
                used+=w;f-=w;
            }
        }
        if(!used)dep[u]=-1;//炸点优化
        return used;
    }

    ll  maxflow() {
        ll ans=0;
        while(BFS()){
            ans+=DFS(S,INF);
        }
        return ans;
    }
}dinic;  
int main(){
    scanf("%d %d",&n,&m);
    dinic.init();
    S=0;T=n+50;
    ll sum=0;
    for(int i=1;i<=n;i++){
        ll p;scanf("%lld",&p);
        if(p>0)dinic.addedge(S,i,p),sum+=p;
        else dinic.addedge(i,T,-p);
    }

    while(m--){
        int u,v;scanf("%d %d",&u,&v);
        dinic.addedge(u,v,INF);
    }

    ll ans=sum-dinic.maxflow();
    dinic.cut(S);
    cout<<dinic.cnt-1<<" "<<ans<<endl;

    // system("pause");
    return 0;
}
View Code

 

 求最大权闭合子图,输出选择方案,

构建最大流求闭合子图权,那么所有流量为正的点即为被选择的点。

 

标签:head,int,子图,ll,Firing,2987,flow,ecnt,dep
来源: https://www.cnblogs.com/littlerita/p/13461749.html