AtCoder Regular Contest 074 F - Lotus Leaves 最小割

4人阅读 评论(0) 收藏 举报
分类:

题意

你的敌对势力计划在一个网格状的迷宫里进行交易。迷宫共有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;
}
查看评论

[最小割] ARC 074 F - Lotus Leaves

SolutionSolution 这样建图:对每一行每一列都建一个点,连向行内的荷叶。 那这道题就相当于删去最少的点使得源汇点不连通。 按这里一样建图就好了。 又忘记写当前弧优化了 #i...
  • Vectorxj
  • Vectorxj
  • 2018-01-10 15:18:15
  • 99

[arc074f]Lotus Leaves

题目大意一个池塘,有起点叶子、终点叶子和叶子。 同行同列的叶子联通,问最少删去多少叶子(除起点终点)能使得起点和终点不连通。最小割显然#include #include #define fo(i,a...
  • WerKeyTom_FTD
  • WerKeyTom_FTD
  • 2017-11-06 22:30:10
  • 153

AtCoder Regular Contest 074 F Lotus Leaves

考虑最小割模型。把每行、每列建成点,加上源点和汇点,一共H+W+2个点。源点向字符S所在的行和列连流量为无穷大的边,T所在的行和列向汇点连流量为无穷大的边,字符o所在的行列之间连流量为1的双向边,割掉...
  • zhan8855
  • zhan8855
  • 2017-05-21 08:48:55
  • 297

ARC 074F Lotus Leaves 最大流最小割

点击打开链接 题意:n*m地图 n,m 先把图变为二分图,每行每列加上源点和汇点,两边点分别为1~n,1~m 对叶子'o'(x,y):x-y连接一条边 表示第x行的叶子可以跳到第y列 流量为1:表...
  • Jeremy1149
  • Jeremy1149
  • 2017-05-22 16:15:04
  • 288

Atcoder Regular Contest 074 F Lotus Leaves

Lotus LeavesProblem Statement给出一个HH*WW 的矩阵,矩阵上有很多水池,有一个水池是起点,一个是终点,从起点出发,每次可以跳到同一行或同一列的水池,问至少要删掉多少个水...
  • XianHaoMing
  • XianHaoMing
  • 2018-02-27 16:19:26
  • 32

【搜索】[AtCoder Regular Contest 092 F]Two Faced Edges

题意: 给出一个有向图,对每条边都做一次询问: 反转这条边后,对原图的强连通分量是否有影响? 点的个数N≤1000N≤1000N\leq 1000,边的个数M≤200000M≤200000M\l...
  • qq_34454069
  • qq_34454069
  • 2018-03-18 20:28:57
  • 68

AtCoder Regular Contest 071 F

题面: 给定n,有多少个长度为无穷的数列{a}满足: 1.对于n 2.对于i 3.1 n solution: 由限制1,得出真正有效的位置只有n个,所以,定义状态f[i]...
  • CRZbulabula
  • CRZbulabula
  • 2017-04-12 18:40:58
  • 553

【AtCoder072F】Dam

题目大意  给你一个水坝,最多装LL升水。每天早上有ViV_i的水流入,温度为tit_i,晚上自由控制流出,但要保证第二天水不会溢出。现求使第ii天满水时水温最大值。   水混合时满足新的体积V=V...
  • llgyc
  • llgyc
  • 2017-05-02 15:28:31
  • 421

AtCoder Regular Contest 077

C 题意:一个序列a,对序列a进行操作,每次吧序列a的第一个元素插入序列b的末端,然后反转序列b,问最后的到的序列b 思路:由题可以反向推理,假设已经有了序列b,然后反转序列b,此时序列b中bn的...
  • sasuke__
  • sasuke__
  • 2017-07-02 17:58:57
  • 165

AtCoder Regular Contest 085 F NRE 线段树优化dp

题意有长度为n初始全为0的数组A和仅由0和1组成的数组B。现在给出m个区间,每次可以选择某个区间[l,r],使得A数组下标在[l,r]之间的元素变为1。问A和B最小不同位置数量是多少。 n,m...
  • qq_33229466
  • qq_33229466
  • 2017-12-02 20:51:29
  • 220
    个人资料
    等级:
    访问量: 0
    积分: 291
    排名: 0
    文章存档
    最新评论