AtCoder Regular Contest 074 F - Lotus Leaves 最小割

题意

你的敌对势力计划在一个网格状的迷宫里进行交易。迷宫共有n 行m 列,
其中一些房间有障碍物无法通行。敌对势力需要从房间S 走到房间T (房间S
和房间T 都没有障碍物)。他们拥有蓝月套装,因此每次可以从一个房间移动
到一个位于同一行或者同一列且没有障碍物的房间。为了阻止敌对势力的交易,
你需要在房间S 和房间T 以外的一些可通行房间内放入障碍,使得他们无法从
房间S 走到房间T。请计算出最少要在多少个房间放障碍。

2<=n,m<=100

分析

很快可以想到,把点拆开,然后中间流一条1的边,割掉花费1,然后一个变成进入的点,一个变成出去的点

这样如果直接每行每列连边的话,是N^2级别的,我们考虑对于一个每行和每列都建一个辅助点,然后就可以变成N+M的级别了

代码

#include <bits/stdc++.h>
#define num(i,j,k) ((((i)-1)*m+(j))*2+k)
using namespace std;
const int N = 1000010;
const int inf = 1e9;
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
struct node
{
  int x,y,c,next;
}edge[N]; int len,first[N];
void ins(int x,int y,int c)
{
  len++; edge[len].x=x; edge[len].y=y; edge[len].c=c; edge[len].next=first[x]; first[x]=len;
  len++; edge[len].x=y; edge[len].y=x; edge[len].c=0; edge[len].next=first[y]; first[y]=len;
}

int n,m; char str[310][310]; int s,d; int tot;

queue<int>q; int dep[N]; 

bool bfs()
{
  while(!q.empty()) q.pop(); q.push(s);
  for(int i=1;i<=tot+n+m;i++) dep[i] = 0; dep[s] = 1;
  while(!q.empty())
  {
    int x = q.front();
    for(int k=first[x];k!=-1;k=edge[k].next)
    {
      int y = edge[k].y;
      if(dep[y] == 0 && edge[k].c)
      {
        dep[y] = dep[x] + 1;
        q.push(y);
      }
    }
    q.pop();
  }
  return dep[d] > 0;
}

int dfs(int x,int flow)
{
  if(x==d || flow == 0) return flow;
  int delta=0;
  for(int k=first[x];k!=-1;k=edge[k].next)
  {
    int y = edge[k].y;
    if(dep[y] == dep[x] + 1 && edge[k].c && flow > delta)
    {
      int minf = dfs(y,min(flow - delta , edge[k].c));
      edge[k].c-=minf; edge[k^1].c+=minf;
      delta+=minf;
    }
  }
  if(delta==0) dep[x] = 0;
  return delta;
}

int main()
{
  len = 1; memset(first,-1,sizeof(first));

  n = read(); m = read();
  for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
  {
    scanf("\n%c",&str[i][j]);
    if(str[i][j] == 'S') s = num(i,j,0);
    else if(str[i][j] == 'T') d = num(i,j,1);
  }

  tot = num(n,m,1);
  for(int i=1;i<=n;i++) // tot + i
  {
    for(int j=1;j<=m;j++) // tot + n + j
    {
      if(str[i][j] == '.') continue;
      if(str[i][j] == 'o') ins(num(i,j,0) , num(i,j,1) , 1);
      else ins(num(i,j,0) , num(i,j,1) , inf);
      ins(num(i,j,1) , tot+i , inf);
      ins(num(i,j,1) , tot+n+j , inf);
      ins(tot+i , num(i,j,0) , inf);
      ins(tot+n+j , num(i,j,0) , inf);
      // printf("(%d,%d) ,  %d %d\n",i,j,i,j);
    }
  }

  int ans = 0;
  while(bfs())
    ans+=dfs(s,inf);
  return printf("%d\n",(ans >= inf) ? -1 : ans),0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页