zoukankan      html  css  js  c++  java
  • BZOJ 4464 旅行时的困惑 最小流

    题面:

      Waldives 有 N 个小岛。目前的交通系统中包含 N-1 条快艇专线,每条快艇
      专线连接两个岛。这 N-1条快艇专线恰好形成了一棵树。
      由于特殊的原因,所有N-1条快艇专线都是单向的。这导致了很多岛屿之间
      不能相互到达。因此,Waldives 政府希望新建一些公交线路,使得建设完毕后,
      任意两个小岛都可以互相到达。为了节约开支,政府希望建设最少的公交线路。 
      同时,出于规划考虑,每一条公交线路都有如下的要求:
      1、每一条交通线路包含若干条连续的快艇专线,你可以认为一条公交线路  
      对应树上的一条路径,而其所包含的若干快艇专线则对应树上被这条路
      径所覆盖的树边(也就是之前已经存在的某个快艇专线);
      2、显然一条交通线路只能覆盖树上任意一条边至多一次;
      3、公交线路中所包含的每一个快艇专线都是有方向的,并且与其所覆盖的
      树边的方向相反;
      4、不同的公交线路可以覆盖树上相同的点或者相同的边。
      Waldives 的 N 个岛屿分别从 0 到 N-1 编号。现在给出 Waldives 已有的快艇
      专线信息,请计算最少所需要新建的交通线路的数量。

    分析:

      这个题……

      复制一下yzy学长的题解吧……觉得说的已经很清楚+精炼了

      让每两个点都能相互到达显然需要覆盖所有的树边从S向每个点连边,从每个点向T连边。每条树边反向连一条下界为1,上界inf的边。跑最小流。

      最小流:

      类似 <有源汇上下界可行流> 的构图方法,但是不添加T到S的边,求一次超级源到超级汇的最大流。
      加边(T,S,0,+∞),在上一步残量网络基础上再求一次超级源到超级汇的最大流。
      流经T到S的边的流量就是最小流的值。
      该算法的思想是在第一步中尽可能填充循环流,以减小最小流的代价。

      数据范围感人……不加当前弧优化过不了……

    代码:

     1 #include<bits/stdc++.h>
     2 #define ms(a,x) memset(a,x,sizeof(a))
     3 #define cpy() for(int i=0;i<=T;i++) cur[i]=h[i]
     4 using namespace std;int S,T,tot=0;
     5 const int N=500005,inf=0x3f3f3f3f;
     6 struct node{int y,z,nxt;}e[N*10];
     7 int a[N],q[N*10],t[N],sm,cur[N];
     8 int c=1,h[N],d[N],m,k,n,ans;
     9 void add(int x,int y,int z){
    10     e[++c]=(node){y,z,h[x]};h[x]=c;
    11     e[++c]=(node){x,0,h[y]};h[y]=c;
    12 } bool bfs(){int f=1,t=0;ms(d,-1);
    13     d[S]=0;q[++t]=S;
    14     while(f<=t){
    15         int x=q[f++];
    16         for(int i=h[x],y;i;i=e[i].nxt)
    17         if(d[y=e[i].y]==-1&&e[i].z)
    18         d[y]=d[x]+1,q[++t]=y;
    19     } return (d[T]!=-1);
    20 } int dfs(int x,int f){
    21     if(x==T) return f;int w,tmp=0;
    22     for(int i=cur[x],y;i;i=e[i].nxt)
    23     if(d[y=e[i].y]==d[x]+1&&e[i].z){
    24         w=dfs(y,min(e[i].z,f-tmp));
    25         if(!w) d[y]=-1;e[i].z-=w;
    26         e[i^1].z+=w;tmp+=w;
    27         if(e[i].z>0) cur[x]=i;
    28         if(tmp==f) return f;
    29     } return tmp;
    30 } void solve(){
    31     while(bfs()){cpy();tot+=dfs(S,inf);}
    32 } int main(){
    33     scanf("%d",&n);int TT=n+1,SS=0;
    34     for(int i=1,y,x;i<n;i++){
    35         scanf("%d%d",&x,&y),x++,y++;
    36         t[y]++;t[x]--;add(x,y,inf);
    37     } S=n+2;T=S+1;
    38     for(int i=1;i<=n;i++)
    39     add(SS,i,inf),add(i,TT,inf);
    40     for(int i=1;i<=n;i++)
    41     if(t[i]>0) add(S,i,t[i]);
    42     else if(t[i]<0) add(i,T,-t[i]);
    43     solve();add(TT,SS,inf);solve();
    44     printf("%d
    ",e[c].z);return 0;
    45 }
    最小流
  • 相关阅读:
    NOI2015 品酒大会
    BJOI2017 喷式水战改
    代码注释
    mysql zip 安装 和 修改密码
    Jrebel 永久免费激活步骤
    layui 在springboot2.x 时,页面展示不了layui的问题
    最小生成树
    loj 10117 简单题(cqoi 2006)
    vijos 1512 SuperBrother打鼹鼠
    vijos 清点人数
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10256945.html
Copyright © 2011-2022 走看看