Sicily 1696. Flows in Grid

训练的题目

最大流

题意:题意直白,就是一个网格从(0,0)编号到(N-1,M-1),每个点可以走到和它相连的4个点,没条边都有容量,为你从(0,0)到(N-1,M-1)的最大流

1.建图细心一点不要出错,注意检查

2.无向图,本来建的是无向图,无端端注释掉一部分,WA了一次才想起来怎么注释掉了,改回来过了

3.建图后,直接上最大流模板,这里用EK

 

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <queue>

using namespace std;

#define N 10100

#define M 100100

#define INF 0x3f3f3f3f



int n,row,col,tot;

int head[N];

struct edge

{

   int u,v,cap,flow,next;

}e[M];



int a[N];  //用于bfs搜索时记录最小残余容量

int p[N];  //邻接表记录路径

queue<int>q;  //用于bfs搜索



void add(int u ,int v , int cap ,int flow)

{

   e[tot].u = u;

   e[tot].v = v;

   e[tot].cap = cap;

   e[tot].flow = flow;

   e[tot].next = head[u];

   head[u] = tot++;

}



void EK(int s ,int t)

{

   int FLOW = 0;

   while(1)

   {

      while(!q.empty()) q.pop();

      memset(a,0,sizeof(a));

      memset(p,-1,sizeof(p));

      a[s] = INF;

      q.push(s);



      while(!q.empty()) //bfs

      {

         int u = q.front();

         q.pop();

         for(int k=head[u]; k!=-1; k=e[k].next)

         {

            int v = e[k].v;

            int cap = e[k].cap;

            int flow = e[k].flow;



            if(!a[v] && cap > flow) //未搜索过,且可以增流

            {

               p[v] = k;  //记录哪条边

               if(a[u] < cap-flow)  a[v] = a[u];

               else                 a[v] = cap - flow;

               q.push(v);

            }

         }

      }



      if(!a[t]) break;  //找不到增广路

      for(int k=p[t]; k!=-1; k=p[e[k].u]) //沿路径返回增广

      {

         e[k].flow += a[t];

         e[k^1].flow -= a[t];

      }

      FLOW += a[t];

   }

   printf("%d\n",FLOW);

}



int main()

{

   int T;

   scanf("%d",&T);

   while(T--)

   {

      scanf("%d%d",&row,&col);

      memset(head,-1,sizeof(head));

      tot = 0;

      n = row * col - 1;

      int cap,u,v;

      //先输入横边

      for(int i=0; i<row; i++)

         for(int j=0; j<col-1; j++)

         {

            scanf("%d",&cap);

            u=i*col+j;    //当前点

            v=i*col+j+1;  //其右边点



            add(u,v,cap,0);  //建立正边u--->v

            add(v,u,0,0);    //反边,容量为0



            add(v,u,cap,0);  //无向图,正边v--->u

            add(u,v,0,0);    //反边,容量为0

         }



      //输入竖边

      for(int i=0; i<row-1; i++)

         for(int j=0; j<col; j++)

         {

            scanf("%d",&cap);

            u=i*col+j;      //当前点

            v=(i+1)*col+j; //其下面的点



            add(u,v,cap,0);  //正边u--->v

            add(v,u,0,0);    //反边,容量为0



            add(v,u,cap,0);   //正边v--->u

            add(u,v,0,0);     //反边,容量为0

         }



      EK(0,n);

   }

   return 0;

}

 

你可能感兴趣的:(grid)