zoukankan      html  css  js  c++  java
  • hdu 3879(最大权闭包)

    题目链接:

    网上一大牛说的好:结论:正的权值的和-建图后的最小割的容量

     选择了一条边就会选择两个点,边的花费为正,点的花费为负,把边看成点,这个点向两个端点连一条边,表示选择这条边就会选择这两个点

    然后题目就相当于最大权闭合图的模型了(最大权闭包模型中vs与正收益的点连边,负收益的点与vt连边,容量取绝对值,然后点与点之间连容量为inf的边)

    题意:有n个点,m个选择,建造n个点各自需要一定花费,每个选择有一定的获利,会选择两个点,当然也要花费。求最大的获利

    每个选择看成是获利点,每个点看成是花费点,新建源点向获利点建边,权值为获利的大小,花费点向汇点建边,权值为花费的大小

    每个选择向相应的两个点连一条容量为无穷大的边,然后求网络的最小割答案就为正的权值和-最小割的容量

    最小割肯定为简单割(直接与源点或汇点相连),在这个题目中,如果与汇点相连的边为割边,表示这个点没有被选择来建station

    如果与源点相连的边为割边,表示不选择某个客户的要求来连接某两个station

    所以可以理解成:最终收益所有可能收益-(损失的收益+架设费用)括号中的即为最小割所求

    View Code
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 #define MAXN 55555
     6 #define MAXM 5555555
     7 #define inf 1<<30
     8 struct Edge{
     9     int v,cap,next;
    10 }edge[MAXM];
    11 
    12 int head[MAXN];
    13 int pre[MAXN];
    14 int cur[MAXN];
    15 int level[MAXN];
    16 int gap[MAXN];
    17 int NE,NV,vs,vt,n,m;
    18 
    19 void Insert(int u,int v,int cap,int cc=0){
    20     edge[NE].v=v;edge[NE].cap=cap;
    21     edge[NE].next=head[u];head[u]=NE++;
    22 
    23     edge[NE].v=u;edge[NE].cap=cc;
    24     edge[NE].next=head[v];head[v]=NE++;
    25 }
    26 
    27 int SAP(int vs,int vt){
    28     memset(pre,-1,sizeof(pre));
    29     memset(level,0,sizeof(level));
    30     memset(gap,0,sizeof(gap));
    31     for(int i=0;i<=NV;i++)cur[i]=head[i];
    32     int u=pre[vs]=vs,maxflow=0,aug=-1;
    33     gap[0]=NV;
    34     while(level[vs]<NV){
    35 loop:
    36         for(int &i=cur[u];i!=-1;i=edge[i].next){
    37             int v=edge[i].v;
    38             if(edge[i].cap&&level[u]==level[v]+1){
    39                 aug==-1?aug=edge[i].cap:aug=min(aug,edge[i].cap);
    40                 pre[v]=u;
    41                 u=v;
    42                 if(v==vt){
    43                     maxflow+=aug;
    44                     for(u=pre[u];v!=vs;v=u,u=pre[u]){
    45                         edge[cur[u]].cap-=aug;
    46                         edge[cur[u]^1].cap+=aug;
    47                     }
    48                     aug=-1;
    49                 }
    50                 goto loop;
    51             }
    52         }
    53         int minlevel=NV;
    54         for(int i=head[u];i!=-1;i=edge[i].next){
    55             int v=edge[i].v;
    56             if(edge[i].cap&&minlevel>level[v]){
    57                 cur[u]=i;
    58                 minlevel=level[v];
    59             }
    60         }
    61         if(--gap[level[u]]==0)break;
    62         level[u]=minlevel+1;
    63         gap[level[u]]++;
    64         u=pre[u];
    65     }
    66     return maxflow;
    67 }
    68 
    69 int main(){
    70     while(~scanf("%d%d",&n,&m)){
    71         vs=0,vt=n+m+1,NV=n+m+2,NE=0;
    72         memset(head,-1,sizeof(head));
    73         int u,v,w,sum=0;
    74         for(int i=1;i<=n;i++){
    75             scanf("%d",&w);
    76             Insert(i,vt,w);
    77         }
    78         for(int i=1;i<=m;i++){
    79             scanf("%d%d%d",&u,&v,&w);
    80             sum+=w;
    81             Insert(vs,i+n,w);//边看成点
    82             Insert(i+n,u,inf);
    83             Insert(i+n,v,inf);
    84         }
    85         printf("%d\n",sum-SAP(vs,vt));
    86     }
    87     return 0;
    88 }
  • 相关阅读:
    Oracle expdp 多表导出处理
    字符串
    Java设计模式
    多线程
    Java面向对象练习
    Java面向对象基础
    Java基础算法
    Java常识
    DOS基础命令(1)
    Java基础练习
  • 原文地址:https://www.cnblogs.com/wally/p/3072030.html
Copyright © 2011-2022 走看看