zoukankan      html  css  js  c++  java
  • bzoj1497 [ NOI2006 ] --最大权闭合子图

    建模:

    将用户群和中转站看成点。对于用户群i,将其向a[i],b[i]连一条边,将c[i]作为它的权值。对于中转站i,将-p[i]作为它的权值。

    然后问题就转化为求图的最大权闭合子图。

    图的闭合子图是指一个点集V,满足对于任意i∈V,i的所有出边指向的点∈V。

    根据定义可以知道,图的闭合子图是允许超过一个联通块的。

    图的最大权闭合子图是一个图中权值和最大的闭合子图。

    怎么求一个图的最大权闭合子图呢?

    我们可以用最小割模型解决。

    对于一个图G,通过下列操作将其转化为网络N=(VN,EN)

    1、对于图中的每条有向边(u,v),连一条容量为无穷大的边(u,v)

    2、对于图中的点v(wv>0),连一条容量为wv的边(s,v)

    3、对于图中的点v(wv<0),连一条容量为-wv的边(v,t)

    那么图的最大权闭合子图就是Σwv(wv>0)-maxflow(N)

    证明就不说了(因为我不会)

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 #define N 5010
     6 #define M 50010
     7 #define INF 2147483647
     8 struct Edge{
     9   int t,c,f,nx;
    10 }e[N+(M<<1)<<2];
    11 int i,j,k,n,m,s,t,h[N+M],Num=1,x,y,Sum,Cur[N+M],q[N+M],l,r,d[N+M];
    12 bool b[N+M];
    13 inline int _Min(int x,int y){return x<y?x:y;}
    14 inline void Add(int x,int y,int c){
    15   e[++Num].t=y;e[Num].c=c;e[Num].nx=h[x];h[x]=Num;
    16   e[++Num].t=x;e[Num].nx=h[y];h[y]=Num;
    17 }
    18 inline bool Bfs(){
    19   l=0;r=1;memset(b,0,sizeof(b));
    20   q[1]=s;b[0]=d[0]=1;
    21   while(++l<=r){
    22     for(int i=h[q[l]];i;i=e[i].nx)
    23       if(e[i].c>e[i].f&&!b[e[i].t]){
    24     b[e[i].t]=1;d[e[i].t]=d[q[l]]+1;q[++r]=e[i].t;
    25       }
    26   }
    27   return b[t];
    28 }
    29 inline int Dfs(int x,int a){
    30   if(a==0||x==t)return a;
    31   int f,F=0;
    32   for(int& i=Cur[x];i;i=e[i].nx)
    33     if(d[x]+1==d[e[i].t]&&(f=Dfs(e[i].t,_Min(a,e[i].c-e[i].f)))){
    34       F+=f;a-=f;e[i].f+=f;e[i^1].f-=f;
    35       if(a==0)break;
    36     }
    37   if(F==0)d[x]=-1;
    38   return F;
    39 }
    40 inline int Dinic(){
    41   int f=0;
    42   while(Bfs()){
    43     for(int i=s;i<=t;i++)Cur[i]=h[i];
    44     f+=Dfs(s,INF);
    45   }
    46   return f;
    47 }
    48 int main()
    49 {
    50   scanf("%d%d",&n,&m);
    51   s=0;t=n+m+1;
    52   for(i=1;i<=n;i++)scanf("%d",&x),Add(i,t,x);
    53   for(i=1;i<=m;i++){
    54     scanf("%d%d%d",&x,&y,&k);
    55     Sum+=k;
    56     Add(i+n,x,INF);
    57     Add(i+n,y,INF);
    58     Add(s,i+n,k);
    59   }
    60   printf("%d",Sum-Dinic());
    61   return 0;
    62 }
    bzoj1497
  • 相关阅读:
    android NDK环境搭建
    Android 控制硬件加速hardwareAccelerated的说明
    如何使用ttf字体文件
    33 文件IO流(二)
    32 文件IO流(一)
    # 02 公共前缀问题
    01 对称匹配问题(总元素必为偶数个)
    31 包装类
    30 常用工具类(二)
    01.数组内容打印(String形式)
  • 原文地址:https://www.cnblogs.com/gjghfd/p/6424455.html
Copyright © 2011-2022 走看看