(二分最大流) 最大流 + 二分查找 小结

  做最大流题目的时候会遇到一种需要用二分查找的题型:

    (poj2455) 一张无向图中有 N 个点,M 条边,每条边都有一个权值,且每条边只能用一次,要求找出 T 条从 1 到 N 的路径,使这 T 条路径所经过的边中,权值的最大值最小。

  转化为最大流模型:T就是最大流,每条边只能用一次在网络流中就是容量为1。然后二分查找(枚举),边权小于或等于mid的边就加一条容量为1的网络流的边。最后知道最大流ans与T相等的最小的mid就是所求。

  在二分查找的时候,与一般的二分查找还是有区别的,一般不能有“ if(ans==T) break;” 这样的语句,因为这种语句使用的条件是函数严格递增,但是我们遇到的题目中很可能会有相邻的函数值相等的情况。

  一般情况下,二分写成这样:

    while(a<=b)
        {
            c=(a+b)/2;
             ……
       if(ans>=sum) {res=c;b=c-1;}
            else a=c+1;
        }

  res就是我们所求的答案。

  

  其实这种题型的建图还是有套路可以找的,多做些题目就有思路了。

  hdu3081 Marriage Match II   第一次做这种类型的题目可能会没思路。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N=220;
  7 const int M=200000, INF=0x3f3f3f3f;
  8 struct node
  9 {
 10     int to,next,w;
 11 }edge[M];
 12 int head[N],numh[N],h[N],cure[N],pre[N],f[N],vis[N][N];
 13 int ans,tot,mid;
 14 void SAP(int s, int e,int n)
 15 {
 16     int flow,u,tmp,neck,i;
 17     ans=0;
 18     memset(pre,-1,sizeof(pre));
 19     memset(h,0,sizeof(h));
 20     memset(numh,0,sizeof(numh));
 21     for(i=1;i<=n;i++)
 22         cure[i]=head[i];
 23     numh[0]=n;
 24     u=s;
 25     while(h[s]<n)
 26     {
 27         if(u==e)
 28         {
 29             flow =INF;
 30             for(i=s;i!=e;i=edge[cure[i]].to)
 31             {
 32                 if(flow>edge[cure[i]].w)
 33                 {
 34                     neck=i;
 35                     flow =edge[cure[i]].w;
 36                 }
 37             }
 38             for(i=s;i!=e;i=edge[cure[i]].to)
 39             {
 40                 tmp=cure[i];
 41                 edge[tmp].w-=flow;
 42                 edge[tmp^1].w+=flow;
 43             }
 44             ans+=flow;
 45             u=neck;
 46         }
 47         for(i=cure[u];i!=-1;i=edge[i].next)
 48             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
 49         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
 50         else
 51         {
 52             if(0==--numh[h[u]]) break; //GAPÓÅ»¯
 53             cure[u]=head[u];
 54             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
 55                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
 56             h[u]=tmp+1;
 57             ++numh[h[u]];
 58             if(u!=s) u=pre[u];
 59         }
 60     }
 61 }
 62 void addedge(int i,int j,int w)
 63 {
 64     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
 65     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
 66 }
 67 int Find(int x){return x==f[x]?x:f[x]=Find(f[x]);}
 68 void Link(int x,int y)
 69 {
 70     int a=Find(x),b=Find(y);
 71     if(a!=b) {f[b]=a;}
 72 }
 73 int B[M],G[M];
 74 int main()
 75 {
 76     //freopen("test.txt","r",stdin);
 77     int cas,i,j,k,n,m,x,y,s,e,d,a,b;
 78     scanf("%d",&cas);
 79     while(cas--)
 80     {
 81         scanf("%d%d%d",&n,&m,&d);
 82         for(i=1;i<=n;i++) f[i]=i;
 83         s=2*n+1;e=s+1;
 84         for(k=1;k<=m;k++)
 85             scanf("%d%d",&G[k],&B[k]);
 86         while(d--)
 87         {
 88             scanf("%d%d",&x,&y);
 89             Link(x,y);
 90         }
 91         x=0,y=n;
 92         while(x<=y)
 93         {
 94             mid=(x+y)/2;
 95             tot=0;
 96             memset(head,-1,sizeof(head));
 97             memset(vis,0,sizeof(vis));
 98             for(i=1;i<=n;i++){
 99                 addedge(s,i,mid);
100                 addedge(i+n,e,mid);
101             }
102             for(i=1;i<=m;i++)
103             {
104                 for(j=1;j<=n;j++)
105                 {
106                     a=Find(G[i]),b=Find(j);
107                     if(a==b&&!vis[j][B[i]]) {addedge(j,B[i]+n,1);
108                     vis[j][B[i]]=1;}
109                 }
110             }
111             SAP(s,e,e);
112             if(ans>=n*mid) {d=mid;x=mid+1;}
113             else y=mid-1;
114         }
115         printf("%d\n",d);
116     }
117     return 0;
118 }

  

  hdu3277 Marriage Match III 与上面一题类似,多了拆点。拆点可以认为是把有N种属性的物品当为N个物品,但是他们之间还是有联系的。

  

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6
  7 const int N=800;
  8 const int M=1100000, INF=10000000;
  9 struct node
 10 {
 11     int to,next,w;
 12 }edge[M];
 13 int head[N],numh[N],h[N],cure[N],pre[N];
 14 int ans,n,tot;
 15 int f[N],G[M],B[M],mat[N][N];
 16 void SAP(int s, int e,int n)
 17 {
 18     int flow,u,tmp,neck,i;
 19     ans=0;
 20     memset(pre,-1,sizeof(pre));
 21     memset(h,0,sizeof(h));
 22     memset(numh,0,sizeof(numh));
 23     for(i=1;i<=n;i++)
 24         cure[i]=head[i];
 25     numh[0]=n;
 26     u=s;
 27     while(h[s]<n)
 28     {
 29         if(u==e)
 30         {
 31             flow =INF;
 32             for(i=s;i!=e;i=edge[cure[i]].to)
 33             {
 34                 if(flow>edge[cure[i]].w)
 35                 {
 36                     neck=i;
 37                     flow =edge[cure[i]].w;
 38                 }
 39             }
 40             for(i=s;i!=e;i=edge[cure[i]].to)
 41             {
 42                 tmp=cure[i];
 43                 edge[tmp].w-=flow;
 44                 edge[tmp^1].w+=flow;
 45             }
 46             ans+=flow;
 47             u=neck;
 48         }
 49         for(i=cure[u];i!=-1;i=edge[i].next)
 50             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
 51         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
 52         else
 53         {
 54             if(0==--numh[h[u]]) break; //GAPÓÅ»¯
 55             cure[u]=head[u];
 56             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
 57                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
 58             h[u]=tmp+1;
 59             ++numh[h[u]];
 60             if(u!=s) u=pre[u];
 61         }
 62     }
 63 }
 64 void init()
 65 {
 66     for(int i=1;i<N;i++) f[i]=i;
 67     memset(mat,0,sizeof(mat));
 68 }
 69 void addedge(int i,int j,int w)
 70 {
 71     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
 72     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
 73 }
 74 int Find(int x){return x==f[x]?x:f[x]=Find(f[x]);}
 75 void Link(int x,int y)
 76 {
 77     int a=Find(x),b=Find(y);
 78     if(a!=b) f[b]=a;
 79 }
 80 int main()
 81 {
 82     //freopen("test.txt","r",stdin);
 83     int m,n,f,i,j,k,cas,s,e;
 84     scanf("%d",&cas);
 85     while(cas--)
 86     {
 87         scanf("%d%d%d%d",&n,&m,&k,&f);
 88         init();
 89         s=3*n+1; e=s+1;
 90         for(i=1;i<=m;i++)
 91         {
 92             scanf("%d%d",&G[i],&B[i]);
 93         }
 94         while(f--)
 95         {
 96             scanf("%d%d",&i,&j);
 97             Link(i,j);
 98         }
 99         for(i=1;i<=m;i++)
100         {
101             int g=Find(G[i]);
102             mat[g][B[i]]=1;
103         }
104         int a=0,b=n,mid;
105         while(a<=b)
106         {
107             mid=(a+b)/2;
108             tot=0;
109             memset(head,-1,sizeof(head));
110             for(i=1;i<=n;i++)
111             {
112                 addedge(s,i,mid);
113                 addedge(i,i+n,k);
114                 addedge(2*n+i,e,mid);
115             }
116             for(i=1;i<=n;i++)
117             {
118                 for(j=1;j<=n;j++)
119                 {
120                     if(mat[Find(i)][j]) addedge(i,j+2*n,1);
121                     else addedge(i+n,j+2*n,1);
122                 }
123             }
124             SAP(s,e,e);
125             if(ans>=n*mid) {a=mid+1;f=mid;}
126             else b=mid-1;
127         }
128         printf("%d\n",f);
129     }
130     return 0;
131 }

  

  poj2112  Optimal Milking 这种类型的基本题。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N =250, M=100000,INF=0x3f3f3f3f;
  7 int Map[N][N], dist[N][N], pre[N];
  8 void floyd(int n)
  9 {
 10     int i,j,k;
 11     for(i=1;i<=n;i++)
 12     {
 13         for(j=1;j<=n;j++)
 14         {
 15             dist[i][j]=Map[i][j];
 16         }
 17     }
 18     for(k=1;k<=n;k++)
 19         for(i=1;i<=n;i++)
 20             for(j=1;j<=n;j++)
 21                 if(dist[i][k]!=INF&&dist[k][j]!=INF&&
 22                    dist[i][k]+dist[k][j]<dist[i][j])
 23                 {
 24                     dist[i][j]=dist[i][k]+ dist[k][j];
 25                 }
 26 }
 27 struct node
 28 {
 29     int to,next,w;
 30 }edge[M];
 31 int head[N],numh[N],h[N],cure[N];
 32 int ans,tot;
 33 void SAP(int s, int e,int n)
 34 {
 35     int flow,u,tmp,neck,i;
 36     ans=0;
 37     for(i=1;i<=n;i++)
 38         cure[i]=head[i];
 39     numh[0]=n;
 40     u=s;
 41     while(h[s]<n)
 42     {
 43         if(u==e)
 44         {
 45             flow =INF;
 46             for(i=s;i!=e;i=edge[cure[i]].to)
 47             {
 48                 if(flow>edge[cure[i]].w)
 49                 {
 50                     neck=i;
 51                     flow =edge[cure[i]].w;
 52                 }
 53             }
 54             for(i=s;i!=e;i=edge[cure[i]].to)
 55             {
 56                 tmp=cure[i];
 57                 edge[tmp].w-=flow;
 58                 edge[tmp^1].w+=flow;
 59             }
 60             ans+=flow;
 61             u=neck;
 62         }
 63         for(i=cure[u];i!=-1;i=edge[i].next)
 64             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
 65         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
 66         else
 67         {
 68             if(0==--numh[h[u]]) break; //GAPÓÅ»¯
 69             cure[u]=head[u];
 70             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
 71                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
 72             h[u]=tmp+1;
 73             ++numh[h[u]];
 74             if(u!=s) u=pre[u];
 75         }
 76     }
 77 }
 78 void init()
 79 {
 80     tot=0;
 81     memset(head,-1,sizeof(head));
 82     memset(pre,-1,sizeof(pre));
 83     memset(h,0,sizeof(h));
 84     memset(numh,0,sizeof(numh));
 85
 86 }
 87 void addedge(int i,int j,int w)
 88 {
 89     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
 90     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
 91 }
 92 int main()
 93 {
 94     //freopen("test.txt","r",stdin);
 95     int k,c,m,i,j,t,s,e,n,R,L,mid;
 96     while(scanf("%d%d%d",&k,&c,&m)!=EOF)
 97     {
 98         n=k+c;
 99         for(i=1;i<=n;i++)
100             for(j=1;j<=n;j++)
101             {
102                 Map[i][j]=INF;
103                 scanf("%d",&t);
104                 if(i==j) continue;
105                 if(t!=0) Map[i][j]=t;
106             }
107         floyd(n);
108         R=L=0;
109         for(i=1;i<=n;i++)
110             for(j=1;j<=n;j++)
111                 if(dist[i][j]!=INF) R=max(R,dist[i][j]);
112         s=n+1;e=s+1;
113         while(L<=R)
114         {
115             mid=(R+L)/2;
116             init();
117             for(i=1;i<=k;i++) addedge(s,i,m);
118             for(i=1;i<=c;i++) addedge(i+k,e,1);
119             for(i=1;i<=k;i++)
120                 for(j=k+1;j<=n;j++)
121                     if(dist[i][j]<=mid) addedge(i,j,1);
122             SAP(s,e,e);
123             if(ans>=c) R=mid-1,t=mid;
124             else L=mid+1;
125         }
126         printf("%d\n",t);
127     }
128     return 0;
129 }

  poj3228  Gold Transportation

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6
  7 const int N=410;
  8 const int M=100000, INF=0x3f3f3f3f;
  9 struct node
 10 {
 11     int to,next,w;
 12 }edge[M];
 13 int head[N],numh[N],h[N],cure[N],pre[N];
 14 int ans,tot;
 15 void SAP(int s, int e,int n)
 16 {
 17     int flow,u,tmp,neck,i;
 18     ans=0;
 19     for(i=1;i<=n;i++)
 20         cure[i]=head[i];
 21     numh[0]=n;
 22     u=s;
 23     while(h[s]<n)
 24     {
 25         if(u==e)
 26         {
 27             flow =INF;
 28             for(i=s;i!=e;i=edge[cure[i]].to)
 29             {
 30                 if(flow>edge[cure[i]].w)
 31                 {
 32                     neck=i;
 33                     flow =edge[cure[i]].w;
 34                 }
 35             }
 36             for(i=s;i!=e;i=edge[cure[i]].to)
 37             {
 38                 tmp=cure[i];
 39                 edge[tmp].w-=flow;
 40                 edge[tmp^1].w+=flow;
 41             }
 42             ans+=flow;
 43             u=neck;
 44         }
 45         for(i=cure[u];i!=-1;i=edge[i].next)
 46             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
 47         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
 48         else
 49         {
 50             if(0==--numh[h[u]]) break; //GAP优化
 51             cure[u]=head[u];
 52             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
 53                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
 54             h[u]=tmp+1;
 55             ++numh[h[u]];
 56             if(u!=s) u=pre[u];
 57         }
 58     }
 59 }
 60 void init()
 61 {
 62     tot=0;
 63     memset(head,-1,sizeof(head));
 64     memset(pre,-1,sizeof(pre));
 65     memset(h,0,sizeof(h));
 66     memset(numh,0,sizeof(numh));
 67
 68 }
 69 void addedge(int i,int j,int w)
 70 {
 71     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
 72     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
 73 }
 74 struct ND
 75 {
 76     int u,v,w;
 77 }e[M];
 78 int g[N],p[N];
 79 int main()
 80 {
 81     //freopen("test.txt","r",stdin);
 82     int n,m,i,j,k,s,E,a,b,c,sum,res,s1;
 83     while(scanf("%d",&n)!=EOF)
 84     {
 85         if(!n) break;
 86         sum=0;s1=0;
 87         for(i=1;i<=n;i++) {scanf("%d",&g[i]); sum+=g[i]; }
 88         for(i=1;i<=n;i++) {scanf("%d",&p[i]); s1+=p[i];}
 89         scanf("%d",&m);
 90         a=INF; b=0;
 91         int t=0;
 92         while(m--){
 93             scanf("%d%d%d",&i,&j,&k);
 94             e[t].u=i;e[t].v=j;e[t].w=k;t++;
 95             a=min(a,k); b=max(b,k);
 96         }
 97         if(sum>s1) {printf("No Solution\n");continue;}
 98         s=n+1; E=s+1;res=-1;
 99         while(a<=b)
100         {
101             c=(a+b)/2;
102             init();
103             for(i=1;i<=n;i++)
104             {
105                 if(g[i])addedge(s,i,g[i]);
106                 if(p[i])addedge(i,E,p[i]);
107             }
108             for(i=0;i<t;i++)
109                 if(e[i].w<=c) addedge(e[i].u,e[i].v,INF),addedge(e[i].v,e[i].u,INF);
110             SAP(s,E,E);
111             if(ans>=sum) {res=c;b=c-1;}
112             else a=c+1;
113         }
114         if(res==-1) printf("No Solution\n");
115         else printf("%d\n",res);
116     }
117     return 0;
118 }

  poj2455  Secret Milking Machine

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N=210;
  7 const int M=100000, INF=0x3f3f3f3f;
  8 struct node
  9 {
 10     int to,next,w;
 11 }edge[M];
 12 struct ND
 13 {
 14     int u,v,w;
 15 }e[40010];
 16 int head[N],numh[N],h[N],cure[N],pre[N];
 17 int ans,tot;
 18 void SAP(int s, int e,int n)
 19 {
 20     int flow,u,tmp,neck,i;
 21     ans=0;
 22     for(i=1;i<=n;i++)
 23         cure[i]=head[i];
 24     numh[0]=n;
 25     u=s;
 26     while(h[s]<n)
 27     {
 28         if(u==e)
 29         {
 30             flow =INF;
 31             for(i=s;i!=e;i=edge[cure[i]].to)
 32             {
 33                 if(flow>edge[cure[i]].w)
 34                 {
 35                     neck=i;
 36                     flow =edge[cure[i]].w;
 37                 }
 38             }
 39             for(i=s;i!=e;i=edge[cure[i]].to)
 40             {
 41                 tmp=cure[i];
 42                 edge[tmp].w-=flow;
 43                 edge[tmp^1].w+=flow;
 44             }
 45             ans+=flow;
 46             u=neck;
 47         }
 48         for(i=cure[u];i!=-1;i=edge[i].next)
 49             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
 50         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
 51         else
 52         {
 53             if(0==--numh[h[u]]) break; //GAP优化
 54             cure[u]=head[u];
 55             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
 56                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
 57             h[u]=tmp+1;
 58             ++numh[h[u]];
 59             if(u!=s) u=pre[u];
 60         }
 61     }
 62 }
 63 void init()
 64 {
 65     tot=0;
 66     memset(head,-1,sizeof(head));
 67     memset(pre,-1,sizeof(pre));
 68     memset(h,0,sizeof(h));
 69     memset(numh,0,sizeof(numh));
 70 }
 71 void addedge(int i,int j,int w)
 72 {
 73     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
 74     edge[tot].to=i;edge[tot].w=w;edge[tot].next=head[j];head[j]=tot++;
 75 }
 76 bool  cmp(const ND &a, const ND &b)
 77 {
 78     return a.w<b.w;
 79 }
 80 int main()
 81 {
 82     //freopen("test.txt","r",stdin);
 83     int n,p,T,i,j,k,R,L,m,s;
 84     scanf("%d%d%d",&n,&p,&T);
 85     R=0;L=INF;
 86     for(i=0;i<p;i++)
 87     {
 88         scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
 89         k=e[i].w;
 90         R=max(R,k);
 91         L=min(L,k);
 92     }
 93     sort(e,e+p,cmp);
 94     while(L<=R)
 95     {
 96         init();
 97         m=(L+R)/2;
 98         for(i=0;i<p;i++)
 99         {
100             if(e[i].w>m)break;
101             addedge(e[i].u,e[i].v,1);
102         }
103         SAP(1,n,n);
104         if(ans>=T) {s=m; R=m-1;}
105         else L=m+1;
106     }
107     printf("%d\n",m);
108     return 0;
109 }

  

  poj2391  Ombrophobic Bovines

  此题是这种类型中较难的题目,综合性挺高的。需要用floyd求任意两点之间的最短距离,然后二分查找。最烦的是超出了int范围,需要修改好几处。并且最不顺心的是习惯上用的二分查找在这里过不了。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N =500,M=1000000;
  7 const long long INF=0x3f3f3f3f3f3f;
  8 long long  Map[N][N], dist[N][N],ans;
  9 void floyd(int n)
 10 {
 11     int i,j,k;
 12     for(i=1;i<=n;i++)
 13     {
 14         for(j=1;j<=n;j++)
 15         {
 16             dist[i][j]=Map[i][j];
 17         }
 18     }
 19     for(k=1;k<=n;k++)
 20         for(i=1;i<=n;i++)
 21             for(j=1;j<=n;j++)
 22                 if(dist[i][k]!=INF&&dist[k][j]!=INF&&
 23                    dist[i][k]+dist[k][j]<dist[i][j])
 24                 {
 25                     dist[i][j]=dist[i][k]+ dist[k][j];
 26                 }
 27 }
 28 struct node
 29 {
 30     int to,next,w;
 31 }edge[M];
 32 int head[N],numh[N],h[N],cure[N],pre[N];
 33 int tot;
 34 void SAP(int s, int e,int n)
 35 {
 36     int u,tmp,neck,i;
 37     long long flow;
 38     ans=0;
 39     for(i=1;i<=n;i++)
 40         cure[i]=head[i];
 41     numh[0]=n;
 42     u=s;
 43     while(h[s]<n)
 44     {
 45         if(u==e)
 46         {
 47             flow =INF;
 48             for(i=s;i!=e;i=edge[cure[i]].to)
 49             {
 50                 if(flow>edge[cure[i]].w)
 51                 {
 52                     neck=i;
 53                     flow =edge[cure[i]].w;
 54                 }
 55             }
 56             for(i=s;i!=e;i=edge[cure[i]].to)
 57             {
 58                 tmp=cure[i];
 59                 edge[tmp].w-=flow;
 60                 edge[tmp^1].w+=flow;
 61             }
 62             ans+=flow;
 63             u=neck;
 64         }
 65         for(i=cure[u];i!=-1;i=edge[i].next)
 66             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
 67         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
 68         else
 69         {
 70             if(0==--numh[h[u]]) break; //GAP优化
 71             cure[u]=head[u];
 72             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
 73                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
 74             h[u]=tmp+1;
 75             ++numh[h[u]];
 76             if(u!=s) u=pre[u];
 77         }
 78     }
 79 }
 80 void init()
 81 {
 82     tot=0;
 83     memset(head,-1,sizeof(head));
 84     memset(pre,-1,sizeof(pre));
 85     memset(h,0,sizeof(h));
 86     memset(numh,0,sizeof(numh));
 87
 88 }
 89 void addedge(int i,int j,int w)
 90 {
 91     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
 92     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
 93 }
 94 int c[N],x[N];
 95 int main()
 96 {
 97     //freopen("test.txt","r",stdin);
 98     int n,m,i,j,k;
 99     long long res,L,R,mid,s1,s2,w;
100     while(scanf("%d%d",&n,&m)!=EOF){
101         for(i=1;i<=n;i++)
102         {
103             Map[i][i]=0;
104             for(j=i+1;j<=n;j++)
105                 Map[j][i]=Map[i][j]=INF;
106         }
107         s1=s2=0;
108         for(i=1;i<=n;i++)
109         {
110             scanf("%d%d",&x[i],&c[i]);
111             s1+=x[i];s2+=c[i];
112         }
113
114         while(m--)
115         {
116             scanf("%d%d%I64d",&i,&j,&w);
117             Map[i][j]=Map[j][i]=min(w,Map[i][j]);
118         }
119         if(s1>s2) {printf("-1\n");continue;}
120         for(i=1;i<=n;i++)
121             if(x[i]>c[i]) break;
122         if(i>n) {printf("0\n");continue;}
123         floyd(n);
124         int s=2*n+1,e=s+1;
125         L=0,res=-1,R=INF;
126         while(L<R)
127         {
128             init();
129             mid=(R+L)/2;
130             for(i=1;i<=n;i++)
131             {
132                 addedge(i,i+n,INF);
133                 addedge(s,i,x[i]);
134                 addedge(i+n,e,c[i]);
135                 for(j=1;j<=n;j++)
136                 {
137                     if(i==j) continue;
138                     if(dist[i][j]<=mid) addedge(i,j+n,INF);
139                 }
140             }
141             SAP(s,e,e);
142             if(ans>=s1) {res=mid; R=mid;}
143             else L=mid+1;
144         }
145         printf("%I64d\n",res);
146     }
147     return 0;
148 }

我的代码中最大流算法都是用的优化的SAP算法,因为他的时间复杂度低。并且我已经习惯了这代码。

SAP模版:

 1 const int N=110;
 2 const int M=2*N*N, INF=0x3f3f3f3f;
 3 struct node
 4 {
 5     int to,next,w;
 6 }edge[M];
 7 int head[N],numh[N],h[N],cure[N],pre[N];
 8 int ans,tot;
 9 void SAP(int s, int e,int n)
10 {
11     int flow,u,tmp,neck,i;
12     ans=0;
13     for(i=1;i<=n;i++)
14         cure[i]=head[i];
15     numh[0]=n;
16     u=s;
17     while(h[s]<n)
18     {
19         if(u==e)
20         {
21             flow =INF;
22             for(i=s;i!=e;i=edge[cure[i]].to)
23             {
24                 if(flow>edge[cure[i]].w)
25                 {
26                     neck=i;
27                     flow =edge[cure[i]].w;
28                 }
29             }
30             for(i=s;i!=e;i=edge[cure[i]].to)
31             {
32                 tmp=cure[i];
33                 edge[tmp].w-=flow;
34                 edge[tmp^1].w+=flow;
35             }
36             ans+=flow;
37             u=neck;
38         }
39         for(i=cure[u];i!=-1;i=edge[i].next)
40             if(edge[i].w && h[u]==h[edge[i].to]+1) break;
41         if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
42         else
43         {
44             if(0==--numh[h[u]]) break; //GAP优化
45             cure[u]=head[u];
46             for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
47                 if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
48             h[u]=tmp+1;
49             ++numh[h[u]];
50             if(u!=s) u=pre[u];
51         }
52     }
53 }
54 void init()
55 {
56     tot=0;
57     memset(head,-1,sizeof(head));
58     memset(pre,-1,sizeof(pre));
59     memset(h,0,sizeof(h));
60     memset(numh,0,sizeof(numh));
61
62 }
63 void addedge(int i,int j,int w)
64 {
65     edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
66     edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
67 }

时间: 2024-11-02 06:36:35

(二分最大流) 最大流 + 二分查找 小结的相关文章

POJ 2455Secret Milking Machine(二分+网络流之最大流)

题目地址:POJ2455 手残真浪费时间啊..又拖到了今天才找出了错误..每晚两道题不知不觉又变回了每晚一道题...sad.. 第一次在isap中忘记调用bfs,第二次则是遍历的时候居然是从1开始遍历的...sad... 这题思路倒是很简单,就是有一个比较坑的地方,就是这里的重边要当两条边来用,以前受最短路什么的影响,直接把慢的删了,很明显不对...这里的两条重边都是可以走的. 建图思路是,将1当作源点,将n当作汇点.右边的地方就连边,注意是无向边.最后判断最大流是否等于道路条数.二分找最小值.

bzoj 2285 [Sdoi2011]保密(二分,spfa + 最大流)

Description 现在,保密成为一个很重要也很困难的问题.如果没有做好,后果是严重的.比如,有个人没有自己去修电脑,又没有拆硬盘,后来的事大家都知道了. 当然,对保密最需求的当然是军方,其次才是像那个人.为了应付现在天上飞来飞去的卫星,军事基地一般都会建造在地下. 某K国的军事基地是这样子的:地面上两排大天井共n1个作为出入口,内部是许多除可以共享出入口外互不连通的空腔,每个空腔有且只有两个出入口,并且这两个出入口不会在同一排.为了方便起见,两排出入口分别编号为1,3,5…和2,4,6…并

BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]

3130: [Sdoi2013]费用流 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 960  Solved: 505[Submit][Status][Discuss] Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识.    最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每条边的实际流量都不超

poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分, dinic

poj 2391 Ombrophobic Bovines, 最大流, 拆点, 二分 dinic /* * Author: yew1eb * Created Time: 2014年10月31日 星期五 15时39分22秒 * File Name: poj2391.cpp */ #include <ctime> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring&g

POJ 2391 floyd二分+拆点+最大流

Ombrophobic Bovines Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20904   Accepted: 4494 Description FJ's cows really hate getting wet so much that the mere thought of getting caught in the rain makes them shake in their hooves. They h

转换流,打印流,序列化

微信公众号:菜鸟永恒 第11天 IO流今日内容介绍?    转换流?    序列化流?    打印流?    Properties今日学习目标?    能够阐述编码表的意义?    能够使用转换流读取指定编码的文本文件?    能够使用转换流写入指定编码的文本文件?    能够使用Properties的load方法加载文件中配置信息?    能够使用Properties的store方法保存配置信息到文件?    能够说出打印流的特点?    能够使用序列化流写出对象到文件?    能够使用反序列

java021.io流 字符流

注意:字节流可以操作任意数据,但是字符流只能操作纯文本文件,一般用于文本文件的只读或只写! 字符流是什么 * 字符流是可以直接读写字符的IO流 * 字符流读取字符, 就要先读取到字节数据, 然后转为字符. 如果要写出字符, 需要把字符转为字节再写出. FileReader类的read()方法可以按照字符大小读取FileWriter类的write()方法可以自动把字符转为字节写出 字符流用处和特点:* 字符流也可以拷贝文本文件, 但不推荐使用. 因为读取时会把字节转为字符, 写出时还要把字符转回字

转换流以及流规律总结

 转换流: 上边读取键盘录入的代码,与BufferedReader的readLine()方法很相似,那么能不能用readLine()来代替?因为System.in是字节流,它要使用字符流缓冲区的方法,这就需要使用到两个转换流:InputStreamReader和OutputStreamWriter. package tan; import java.io.*; public class TranStreamDemo { public static void main(String[] args)

字符流/转换流

字符流/转换流:由于字节流操作中文不方便,所以出现了. 总共有以下方法: 1.InputStreamReader.OutputStreamWriter 2.FileReader.FileWriter 3.BufferedReader BufferedWriter的普通方法 4.BufferedReader BufferedWriter的特殊方法 字符流=字节流+编码表 编码的方法: byte[] getBytes(String charsetName):使用指定的字符集合把字符编码成字节数组  

Java IO之处理流(缓冲流、转换流)

一.处理流: 增强功能,提供性能,在节点流之上. 二.节点流与处理流的关系 节点流(字节流.字符流)处于IO操作的第一线,所有操作必须通过它们进行: 处理流可以对其他流进行处理(提高效率或操作灵活性). 三.缓冲流 1.字节缓冲流 BufferedInputStream BufferedOutputStream package IOBuffer; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; im