zoukankan      html  css  js  c++  java
  • POJ 2987

    题意:求一个图的最大权闭合子图

    教科书:https://blog.csdn.net/can919/article/details/77603353

    最小割模型的应用,源点向正权点建容量为该权值的弧;负权点向汇点建容量为该权值绝对值的弧;有偏序关系的点对之间建容量为正无穷的弧.
    跑出最大流,根据最大流最小割定理:最大流的值即最小割.所求最大闭合子图的值为|正权点权值之和| - |最小割|.
    此外,还要求删去人的数目.那么从源点出发,且不是最小割的边,就是被选择的边.
    所以从源点dfs,若遇到容量不为0的边则结果++.最后记得减去源点

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int MAXN=6010;//点数的最大值
    const int MAXM=100010;//边数的最大值
    #define captype long long
    typedef long long LL;
    const LL INF = (1LL)<<60;
    
    struct SAP_MaxFlow{
        struct EDGE{
            int to,next;
            captype cap;
        }edg[MAXM];
        int eid,head[MAXN];
        int gap[MAXN];
        int dis[MAXN];
        int cur[MAXN];
        int pre[MAXN];
    
        void init(){
            eid=0;
            memset(head,-1,sizeof(head));
        }
        void AddEdge(int u,int v,captype c,captype rc=0){
            edg[eid].to=v; edg[eid].next=head[u];
            edg[eid].cap=c;  head[u]=eid++;
            edg[eid].to=u; edg[eid].next=head[v];
            edg[eid].cap=rc; head[v]=eid++;
        }
        captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
            memset(gap,0,sizeof(gap));
            memset(dis,0,sizeof(dis));
            memcpy(cur,head,sizeof(head));
            pre[sNode] = -1;
            gap[0]=n;
            captype ans=0;
            int u=sNode;
            while(dis[sNode]<n){
                if(u==eNode){
                    captype Min=INF ;
                    int inser;
                    for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])
                    if(Min>edg[i].cap){
                        Min=edg[i].cap;
                        inser=i;
                    }
                    for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
                        edg[i].cap-=Min;
                        edg[i^1].cap+=Min;
                    }
                    ans+=Min;
                    u=edg[inser^1].to;
                    continue;
                }
                bool flag = false;
                int v;
                for(int i=cur[u]; i!=-1; i=edg[i].next){
                    v=edg[i].to;
                    if(edg[i].cap>0 && dis[u]==dis[v]+1){
                        flag=true;
                        cur[u]=pre[v]=i;
                        break;
                    }
                }
                if(flag){
                    u=v;
                    continue;
                }
                int Mind= n;
                for(int i=head[u]; i!=-1; i=edg[i].next)
                if(edg[i].cap>0 && Mind>dis[edg[i].to]){
                    Mind=dis[edg[i].to];
                    cur[u]=i;
                }
                gap[dis[u]]--;
                if(gap[dis[u]]==0) return ans;
                dis[u]=Mind+1;
                gap[dis[u]]++;
                if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
            }
            return ans;
        }
    }F;
    
    
    bool vis[MAXN];
    int tot = 0;
    void dfs(int u)
    {
        vis[u] = true;
        tot++;
        for(int i=F.head[u];~i;i=F.edg[i].next){
            int v = F.edg[i].to;
            if(!vis[v] && F.edg[i].cap>0){
                dfs(v);
            }
        }
    }
    
    LL val[MAXN];
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        int n,m;
        while(scanf("%d %d",&n,&m)==2){
            F.init();
            LL sum = 0;
            tot=0;
            int s = 0,t = n+1,u,v;
            for(int i=1;i<=n;++i){
                scanf("%lld",&val[i]);
                if(val[i]>0){
                    sum += val[i];                  //统计正权边之和
                    F.AddEdge(s,i,val[i]);
                }
                else{
                    F.AddEdge(i,t,-val[i]);
                }
            }
            for(int i=1;i<=m;++i){
                scanf("%d %d",&u,&v);
                F.AddEdge(u,v,INF);         
            }
            LL f = F.maxFlow_sap(s,t,t+1);
            LL res = sum - f;                       //最大权值为 正权和-最小割
            memset(vis,0,sizeof(vis));
            dfs(s);                                 //计算割的边数
            printf("%d %lld
    ",tot-1,res);          //多算了一个
        }
        return 0;
    }
    
    
    为了更好的明天
  • 相关阅读:
    iframe 的自适应高度
    在repeater、datalist控件中使用分页功能
    多语言网站开发:不完全技术分析
    提高ASP.Net应用程序性能的十大方法
    使用ASP在线解压rar文件
    在C#程序设计中使用Win32类库
    FCKeditor 2.0 的设置.修改.使用
    Windows Server 2003 四种版本的区别
    在ASP中应用FCKeditor2.1.1
    获得汉字的拼音首字母源代码
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9648878.html
Copyright © 2011-2022 走看看