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;
}

 

posted @ 2013-04-30 20:18  Titanium  阅读(171)  评论(0编辑  收藏  举报