zoukankan      html  css  js  c++  java
  • BZOJ-1497 [NOI2006]最大获利 最小割

    题面

    题意:有n个地点可以选择是否修建,建的成本为p[i],用户有M个,对于每个用户,如果地点Ai和Bi都修了的,那么你就可以获得Ci的收益,现在问你最多能获得多少钱

    题解:考虑最小割

       对于每个地点 build(s,i,p[i])
         对于每个用户 build(i+n,t,c[i])
           他所需要的2个地点,build(a[i],i+n,inf);build(b[i],i+n,inf)
           然后用总的收益减去最小割就是答案 Why?
           我们想割掉的是连向s的边 表示我们修了这个地点 成本增加了
           割掉的是连向t的边 表示我们没有赚到这个客户的钱 获利减少了

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 55005
     4 #define M 160000
     5 const int inf=0x7fffffff/3;
     6 namespace Dinic
     7 {
     8     int head[N],head2[N],p=1;
     9     struct Rec
    10     {
    11         int go,nex,c;
    12     }eg[M*2];
    13     void build(int a,int b,int c)
    14     {
    15         eg[++p]=(Rec){b,head[a],-c};
    16         head[a]=p;
    17         eg[++p]=(Rec){a,head[b],0};
    18         head[b]=p;
    19     }
    20     int dis[N],Q[N],s[N],S,T,stop,ans;
    21     bool bfs()
    22     {
    23         memset(dis,0,sizeof(dis));
    24         dis[T]=1;
    25         Q[1]=T;
    26         for (int p1=1,p2=1;p1<=p2;p1++)
    27         {
    28             for (int i=head[Q[p1]];i;i=eg[i].nex)
    29                 if (eg[i^1].c<0&&!dis[eg[i].go])
    30                 {
    31                     dis[eg[i].go]=dis[Q[p1]]+1;
    32                     Q[++p2]=eg[i].go;
    33                 }
    34         }
    35         if (!dis[S]) return false;
    36         memcpy(head2,head,sizeof(head));
    37         return true;
    38     }
    39     bool dinic(int p,int top)
    40     {
    41         if (p==T)
    42         {
    43             int x=inf;
    44             for (int i=1;i<=top-1;i++) if (-eg[s[i]].c<x) x=-eg[s[i]].c,stop=i;
    45             for (int i=1;i<=top-1;i++) eg[s[i]].c+=x,eg[s[i]^1].c-=x;
    46             ans+=x;
    47             return true;
    48         }
    49         for (int &i=head2[p];i;i=eg[i].nex)
    50         {
    51             if (eg[i].c<0&&dis[eg[i].go]==dis[p]-1)
    52             {
    53                 s[top]=i;
    54                 if (dinic(eg[i].go,top+1)&&top!=stop) return true;
    55             }
    56         }
    57         return false;
    58     }
    59     int ask()
    60     {
    61         ans=0;
    62         while (bfs()) dinic(S,1);
    63         return ans; 
    64     }
    65     void init(int _S,int _T){
    66         S=_S,T=_T;
    67     }
    68 }
    69 using namespace Dinic;
    70 void clear()
    71 {
    72     p=1;
    73     memset(head,0,sizeof(head));
    74 }
    75 int n,m,ss,tt,x,y,z,why;
    76 int main()
    77 {
    78     scanf("%d%d",&n,&m);
    79     ss=0;tt=n+m+1;
    80     init(ss,tt);
    81     for (int i=1;i<=n;i++)
    82     {
    83         scanf("%d",&x);
    84         build(ss,i,x);
    85     }
    86     for (int i=1;i<=m;i++)
    87     {
    88         scanf("%d%d%d",&x,&y,&z);
    89         why+=z;
    90         build(i+n,tt,z);
    91         build(y,i+n,inf);
    92         build(x,i+n,inf);
    93     }
    94     printf("%d
    ",why-ask());
    95     return 0;
    96 }
    Anderyi!
  • 相关阅读:
    【LeetCode-链表】环形链表
    【LeetCode-数学】快乐数
    【LeetCode-位运算】只出现一次的数字
    【LeetCode-查找】山脉数组中查找目标值
    【LeetCode-查找】寻找旋转排序数组中的最小值 II
    【LeetCode-查找】寻找旋转排序数组中的最小值
    Linux基础命令mount /umount
    磁盘分区(Gdisk分区)
    磁盘分区( Fdisk分区)
    Linux基础练习题7.31
  • 原文地址:https://www.cnblogs.com/qywhy/p/9717751.html
Copyright © 2011-2022 走看看