• POJ 2391 多源多汇拆点最大流 +flody+二分答案


    题意:在一图中,每个点有俩个属性:现在牛的数量和雨棚大小(下雨时能容纳牛的数量),每个点之间有距离,
    给出牛(速度一样)在顶点之间移动所需时间,问最少时间内所有牛都能避雨。
    模型分析:多源点去多汇点(此题源点也可能是汇点(源汇同点)),所以我的方法是:建立超级源点和超级
    汇点,超级源点连想所有点,容量为该店本来的牛数量,在把各点拆成如图(略丑),到汇点的容量分别为
    避雨容纳量,点点之间容量可以无限大。folyd求任意两点的最短路后,二分最大时间建图,枚举求最大之最小即可。
    未1A原因:
    1:开始时为了偷取一点时间复杂度,源点和汇点的部分图按全局先建立了,导致链式前向星操作失控,
    也因为这样更好的理解了head[i]的作用;
    2:开始没有拆点,这题明显和POJ2112不同,因为目标点(多个)和出发点(多个)可能在同一个点,
    必需拆点i  --》i+n+1(n+1是超级汇点)。
    3.注意此题数据范围,一条边可能到10^10,多边时必然爆INT,用longlong,在函数传参的时候也别忘记!
    还有就是几条边,200*200*2+200*2*2(200个点拆后俩俩有双向边+超级源点和汇点)。

    PS:为什么我的dinic时间要700MS+。。。。







    #include<iostream>//750MS
    #include<cstdio>
    #include<vector>
    #include<queue>
    using namespace std;
    int n,m;const int inf =0x3f3f3f3f;
    long long a[210][210]; long long minmax=0;int num=0;
    int  sh=0; int numcow=0;
    int e[81001][3];int head[410]; int cow[210];int shelt[210];  //链式前向星二维数组表示法,0:to,1:pre,2:wight;
    void folyd()                   //最短路不用说
    {
         for(int i=1;i<=n;i++)
           for(int j=1;j<=n;j++)
             for(int ii=1;ii<=n;ii++)
                    if(a[j][ii]>a[j][i]+a[i][ii])
                       {
                           a[j][ii]=a[j][i]+a[i][ii];
                          if(a[j][ii]>minmax)minmax=a[j][ii];         //枚举上界
                       }
    }
    void build(long long limit)  //建图
    {
           num=0;
         for(int i=0;i<=2*n+2;i++)
            head[i]=-1;
        for(int i=1;i<=n;i++)    //超级源点和汇点
         {
             e[num][0]=i;e[num][1]=head[0];head[0]=num;
             e[num++][2]=cow[i];
             e[num][0]=0;e[num][1]=head[i];head[i]=num;
             e[num++][2]=0;
             e[num][0]=n+1;e[num][1]=head[i+n+1];head[i+n+1]=num;
             e[num++][2]=shelt[i];
             e[num][0]=i+n+1;e[num][1]=head[n+1];head[n+1]=num;
             e[num++][2]=0;
         }
        for(int i=1;i<=n;i++)    //限制下可以添加的边
          for(int j=1;j<=n;j++)
             if(a[i][j]<=limit)
               {
                   e[num][0]=j+n+1;e[num][1]=head[i];head[i]=num;
                   e[num++][2]=numcow;
                   e[num][0]=i;e[num][1]=head[j+n+1];head[j+n+1]=num;
                   e[num++][2]=0;
               }
    }
    int level[410];int vis[410];
    bool bfs()                          //bfs+dfs,dinic算法
    {
        for(int i=0;i<=2*n+2;i++)
           vis[i]=level[i]=0;
         queue<int>q;
        q.push(0);vis[0]=1;
        while(!q.empty())
        {
          int cur=q.front();q.pop();
          for(int i=head[cur];i!=-1;i=e[i][1])
              {    int to=e[i][0];
                  if(!vis[to]&&e[i][2]>0)
                  {
                      vis[to]=1;
                      level[to]=level[cur]+1;
                      if(to==n+1)return 1;
                      q.push(to);
                  }
              }
        }
        return vis[n+1];
    }
    int dfs(int uu,int minf)
    {
        if(uu==n+1||minf==0)return minf;
        int sum=0,f;
         for(int i=head[uu];i!=-1&&minf;i=e[i][1])
              {      int to=e[i][0];
                  if(level[to]==level[uu]+1&&e[i][2]>0)
                  {
                      f=dfs(to,minf<e[i][2]?minf:e[i][2]);
                      e[i][2]-=f;e[i^1][2]+=f;
                      sum+=f;minf-=f;
                  }
              }
          return sum;
    }
    bool check(long long limit)   
    {
        build(limit);
        int sumflow=0;
        while(bfs())
        {
            sumflow+=dfs(0,inf);
        }
        if(sumflow==numcow)
          return 1;
       return 0;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
         for(int i=1;i<=n;i++)
         {
             scanf("%d%d",&cow[i],&shelt[i]);
             numcow+=cow[i]; sh+=shelt[i];
         }
        for(int i=0;i<=n;i++)          
           for(int j=0;j<=n;j++)
                 a[i][j]=10000000000000;
        for(int i=0;i<=n;i++)
             a[i][i]=0;
           for(int j=1;j<=m;j++)
            {
               int temp1,temp2;
               scanf("%d%d",&temp1,&temp2);
               long long tempa;
               scanf("%lld",&tempa);
               if(a[temp1][temp2]>tempa)
               {
                  a[temp1][temp2]=tempa;
                  a[temp2][temp1]=tempa;
                  if(a[temp1][temp2]>minmax)minmax=a[temp1][temp2];         //枚举上界
               }
            }
         if(numcow>sh){printf("-1
    ");return 0;}   //无解情况
        folyd();
        long long left=0,right=minmax,mid;
        if(!check(minmax)){printf("-1
    ");return 0;}   //无解情况
          while(right>left+1)          //二分答案,注意一下
          {
              mid=(right+left)/2;
              if(check(mid))
              {
                  right=mid;
              }
              else
                left=mid;
          }
          if(check(right-1))         //最后二分时判断特殊情况
          printf("%lld
    ",right-1);
          else
            printf("%lld
    ",right);
         return 0;
    }
    



  • 相关阅读:
    Appium——api常用函数
    Appium——元素定位
    Appium——adb 启动问题Invalid argument: cannot open transport registration socketpair could not read ok from ADB Server failed to start daemon * error: cannot connect to daemon
    Appium——Error while obtaining UI hierarchy XML file:com.android.ddmlib.SyncException:
    Appium——解决每次启动时都安装setting和unlock app方法
    Appium——连接真机,adb devices获取不到设备号
    Appium——详解Appium server capabilities
    Appium——WebDriverException: Message: A new session could not be created.
    Appium基础——one demo
    vscode 踩坑汇总
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925744.html
Copyright © 2020-2023  润新知