zoukankan      html  css  js  c++  java
  • bzoj1797 [Ahoi2009]Mincut 最小割

    我们首先跑一遍最大流。

    可以发现如果一个流没跑或者没有跑满,他肯定不再最小割中。如果没跑,那么去掉它之后新图的最小割依然等于最大流,所以割他没有用,而没有跑满的边可以看作是一个满了的边和一个空的边,割了就是浪费了他多余的流量。

    那么如果一个边跑满了呢?

     对于残留网络缩点,如果$id[u]!=id[v]$,那么可能选到这条边。

    如果 $id[u]==id[S]且id[v]==id[T]$ ,那么一定选这条边。

    现在感性理解了,理性证明坑待填。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <iostream>
      5 #include <cmath>
      6 #include <queue>
      7 #define N 4005
      8 #define inf 0x7fffffff
      9 using namespace std;
     10 int n,m,S,T;
     11 int e=2,head[N];
     12 struct edge{
     13     int u,v,f,next;
     14 }ed[120050];
     15 void add(int u,int v,int f){
     16     ed[e].u=u;ed[e].v=v;ed[e].f=f;
     17     ed[e].next=head[u];head[u]=e++;
     18     ed[e].u=v;ed[e].v=u;ed[e].f=0;
     19     ed[e].next=head[v];head[v]=e++;
     20 }
     21 int dep[N];
     22 bool bfs(){
     23     memset(dep,0,sizeof dep);
     24     queue<int> Q;
     25     Q.push(S);dep[S]=1;
     26     while(!Q.empty()){
     27         int x=Q.front();Q.pop();
     28         for(int i=head[x];i;i=ed[i].next){
     29             if(ed[i].f&&!dep[ed[i].v]){
     30                 dep[ed[i].v]=dep[x]+1;
     31                 if(ed[i].v==T)return 1;
     32                 Q.push(ed[i].v);
     33             }
     34         }
     35     }
     36     return 0;
     37 }
     38 int dfs(int x,int f){
     39     if(x==T||!f)return f;
     40     int ans=0;
     41     for(int i=head[x];i;i=ed[i].next){
     42         if(ed[i].f&&dep[ed[i].v]==dep[x]+1){
     43             int nxt=dfs(ed[i].v,min(f,ed[i].f));
     44             ans+=nxt;f-=nxt;ed[i].f-=nxt;ed[i^1].f+=nxt;
     45         }
     46         if(!f)break;
     47     }
     48     if(!ans)dep[x]=-1;
     49     return ans;
     50 }
     51 int dinic(){
     52     int ans=0;
     53     while(bfs())ans+=dfs(S,inf);
     54     return ans;
     55 }
     56 int dfn[N],low[N],top,q[N],id[N],tot;
     57 bool bo[N];
     58 void tarjan(int x){
     59     dfn[x]=low[x]=++top;
     60     q[top]=x;bo[x]=1;
     61     for(int i=head[x];i;i=ed[i].next){
     62         if(ed[i].f){
     63             int v=ed[i].v;
     64             if(!dfn[v]){
     65                 tarjan(v);
     66                 low[x]=min(low[x],low[v]);
     67             }
     68             else if(bo[v]){
     69                 low[x]=min(low[x],dfn[v]);
     70             }
     71         }
     72     }
     73     if(low[x]==dfn[x]){
     74         int y;tot++;
     75         do{
     76             y=q[top--];
     77             id[y]=tot;
     78             bo[y]=0;
     79         }while(y!=x);
     80     }
     81 }
     82 int main(){
     83     scanf("%d%d%d%d",&n,&m,&S,&T);
     84     for(int i=1,u,v,f;i<=m;i++){
     85         scanf("%d%d%d",&u,&v,&f);
     86         add(u,v,f);
     87     }
     88     dinic();
     89     for(int i=1;i<=n;i++)
     90         if(!dfn[i])tarjan(i);
     91     for(int i=2;i<e;i+=2){
     92         if(!ed[i].f){
     93             if(id[ed[i].u]!=id[ed[i].v])printf("1 ");
     94             else printf("0 ");
     95             if(id[ed[i].u]==id[S]&&id[ed[i].v]==id[T])puts("1");
     96             else puts("0");
     97         }
     98         else puts("0 0");
     99     }
    100     return 0;
    101 }
    View Code
  • 相关阅读:
    倍增算法2(树上倍增)
    倍增算法1
    可持久线段树
    【BZOJ】1059: [ZJOI2007]矩阵游戏(二分图匹配)
    【BZOJ】2743: [HEOI2012]采花(树状数组)
    【BZOJ】2959: 长跑(lct+缩点)(暂时弃坑)
    【学习笔记】LCT link cut tree
    【学习笔记】FFT
    【BZOJ】1001: [BeiJing2006]狼抓兔子(最小割 / 对偶图)
    【BZOJ】1007: [HNOI2008]水平可见直线(凸包)
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/8294928.html
Copyright © 2011-2022 走看看