洛谷 2472 [SCOI2007]蜥蜴 题解

博客观赏效果更佳

题意简述

有一个 n × m n\times m n×m 的矩阵,其中一些位置上有蜥蜴。每个位置上有一个石柱,给你他们初始的高度 a i , j a_{i,j} ai,j。一个蜥蜴可以从一个石柱,跳到直线距离 ≤ k \le k k 的另一个石柱上。当一只蜥蜴从一个石柱上离开的时候,这个石柱的高度就会减少 1 1 1 。如果蜥蜴跳到了矩阵外面,就是逃离了。请你求最少有多少只不能逃离(其实就是最多能逃离几只)。

1 < = n , m < = 20 1<=n,m<=20 1<=n,m<=20 k < = 4 k<=4 k<=4

【附】直线距离:从 ( x 1 , y 1 ) (x1,y1) (x1,y1) ( x 2 , y 2 ) (x2,y2) (x2,y2) 的直线距离为: ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 \sqrt{(x1-x2)^2+(y1-y2)^2} (x1x2)2+(y1y2)2

思路框架

显然建网络流。首先我们把矩阵展开,就是把 ( i , j ) (i,j) (i,j) 位置的点编号为 ( i − 1 ) m + j (i-1)m+j (i1)m+j

每个石柱上只能通过定量的蜥蜴,这显然是一个点限流。套路拆点,每个位置变成 I n ( i , j ) In(i,j) In(i,j) O u t ( i , j ) Out(i,j) Out(i,j)。设源点为 S S S ,汇点为 T T T

对于每个点 ( i , j ) (i,j) (i,j)

I n ( i , j ) → a i , j O u t ( i , j ) In(i,j) \xrightarrow[a_{i,j}]{} Out(i,j) In(i,j) ai,jOut(i,j) (一个石柱上只能通过 a i , j a_{i,j} ai,j 个蜥蜴)}
S → 1 I n ( i , j ) S \xrightarrow[1]{} In(i,j) S 1In(i,j) (一个石柱上只能有一个蜥蜴)
O u t ( i , j ) → i n f T Out(i,j) \xrightarrow[inf]{} T Out(i,j) infT (跳出终点就随便了)

对于点 ( i , j ) (i,j) (i,j) 和点 ( u , v ) (u,v) (u,v) 满足 ( i , j ) (i,j) (i,j) ( u , v ) (u,v) (u,v) 直线距离 ≤ k \le k k
O u t ( i , j ) → i n f I n ( u , v ) Out(i,j) \xrightarrow[inf]{} In(u,v) Out(i,j) infIn(u,v) (点之间跳是不限的)
O u t ( u , v ) → i n f I n ( i , j ) Out(u,v) \xrightarrow[inf]{} In(i,j) Out(u,v) infIn(i,j)

这样跑一个最大流即珂。

Q:为什么点到点,点到 T T T 之间都是 i n f inf inf 的边呢?怎么就“随便”了?
A:其实并不是随便,我们知道,网络流上一个流能流过的值是其路径上的最小值。那么既然 I n ( i , j ) In(i,j) In(i,j) O u t ( i , j ) Out(i,j) Out(i,j) 的时候,已经限过了一次 a i , j a_{i,j} ai,j ,那我们从 O u t ( i , j ) Out(i,j) Out(i,j) I n ( u , v ) In(u,v) In(u,v) 的时候,再限一次也没有必要了。当然,你如果实在要限这条边流量为 a i , j a_{i,j} ai,j,没有任何问题。

代码

#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
	#define N 1333
	#define INF 0x3f3f3f3f
	#define F(i,l,r) for(int i=l;i<=r;++i)
	#define D(i,r,l) for(int i=r;i>=l;--i)
	#define Fs(i,l,r,c) for(int i=l;i<=r;c)
	#define Ds(i,r,l,c) for(int i=r;i>=l;c)
	#define MEM(x,a) memset(x,a,sizeof(x))
	#define FK(x) MEM(x,0)
	#define p_b push_back
	#define sz(a) ((int)a.size())
	#define iter(a,p) (a.begin()+p)
	void R1(int &x)
	{
	    x=0;char c=getchar();int f=1;
	    while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
	    while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	    x=(f==1)?x:-x;
	}
	void Rd(int cnt,...)
	{
	    va_list args;
	    va_start(args,cnt);
	    F(i,1,cnt) 
	    {
	        int* x=va_arg(args,int*);R1(*x);
	    }
	    va_end(args);
	}
	class Graph //这些是板子
	{
    public:
        int EdgeCount;
        int head[N];
        struct Edge
        {
            int To,Label;
            int Next;
        }Ed[200100];
        void clear()
        {
            MEM(head,-1);
            MEM(Ed,-1);
            EdgeCount=-1;
        }
        void AddEdge(int u,int v,int w)
        {
            ++EdgeCount;
            Ed[EdgeCount]=(Edge){v,w,head[u]};
            head[u]=EdgeCount;
        }
        void AddFlow(int u,int v,int w)
        {
            AddEdge(u,v,w);
            AddEdge(v,u,0);
        }

        int Source,Sink;
        int deep[N];
        queue<int>Q,EmptyQ;
        bool BFS()
        {
            Q=EmptyQ;
            FK(deep);

            Q.push(Source);
            deep[Source]=1;
            do
            {
                int u=Q.front();Q.pop();
                for(int i=head[u];~i;i=Ed[i].Next)
                {
                    int v=Ed[i].To;
                    if (deep[v]==0 and Ed[i].Label>0)
                    {
                        deep[v]=deep[u]+1;
                        Q.push(v);
                    }
                }
            }while(!Q.empty());

            if (deep[Sink]==0) return 0;
            return 1;
        }
        int DFS(int u,int MinFlow)
        {
            if (u==Sink) return MinFlow;
            for(int i=head[u];~i;i=Ed[i].Next)
            {
                int v=Ed[i].To;
                if (deep[v]==deep[u]+1 and Ed[i].Label!=0)
                {
                    int d=DFS(v,min(MinFlow,Ed[i].Label));
                    if (d>0)
                    {
                        Ed[i].Label-=d;
                        Ed[i^1].Label+=d;
                        return d;
                    }
                }
            }
            return 0;
        }
        int Dinic()
        {
            int ans=0;
            while(BFS())
            {
                int d;
                while(d=DFS(Source,0x3f3f3f3f))
                {
                    ans+=d;
                }
            }
            return ans;
        }
	}Nt;
	#define S Nt.Source
	#define T Nt.Sink
	#define id(i,j,x) (x*n*m+(i-1)*m+j)
	//(x,y,0): In
	//(x,y,1): Out

	int n,m,k; int cnt;
	int a[N][N]; char t[N];
	void Input()
	{
		Rd(3,&n,&m,&k);
		F(i,1,n) F(j,1,m) scanf("%1d",&a[i][j]);
		Nt.clear();
		S=2*n*m+1,T=2*n*m+2;
		F(i,1,n)
		{
			scanf("%s",t+1);
			F(j,1,m) if (t[j]=='L' and a[i][j]>0) 
           //如果一开始石柱就没了,我们就忽略这个蜥蜴
			{
				++cnt;
				Nt.AddFlow(S,id(i,j,0),1); 
			}
		}
	}

	void Soviet()
	{
		F(i,1,n) F(j,1,m)     Nt.AddFlow(id(i,j,0),id(i,j,1),a[i][j]);
        //建In(i,j)到Out(i,j)的边
		F(i,1,n) F(j,1,m) if (i-k<1 or j-k<1 or i+k>n or j+k>m)
		{
			Nt.AddFlow(id(i,j,1),T,INF);
           //建立到终点的边
		}
		F(i,1,n) F(j,1,m) F(u,max(i-k,1),min(i+k,n)) F(v,max(j-k,1),min(j+k,m)) if (a[i][j] and a[u][v])
		{
			if (i==u and v==j) continue;
			if ((i-u)*(i-u)+(j-v)*(j-v)<=k*k)
           //直线距离<=k
			{
				Nt.AddFlow(id(i,j,1),id(u,v,0),INF);
				Nt.AddFlow(id(u,v,1),id(i,j,0),INF);
              //建边
			}
		}
		printf("%d\n",cnt-Nt.Dinic());
       //蜥蜴的数量-最大的能逃脱的数量,就是最少的不能逃脱的数量
	}

	#define Flan void
	Flan IsMyWife()
	{
		Input();
		Soviet();
	}
}
int main()
{
	Flandre_Scarlet::IsMyWife();
	getchar();getchar();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值