zoukankan      html  css  js  c++  java
  • 蜥蜴【网络流】

    ##题目大意:
    在一个rrcc列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。
    每行每列中相邻石柱的距离为11,蜥蜴的跳跃距离是dd,即蜥蜴可以跳到平面距离不超过dd的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减11(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为11,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。


    ##思路:
    很明显的最大流问题。为了满足一个石柱最多跳a[i][j]a[i][j]只蜥蜴,就要将每个石柱进行拆点,中间流量为a[i][j]a[i][j],这样就保证了最多只有a[i][j]a[i][j]只蜥蜴可以跳这个石柱。那么这个建图就很明显了:

    1. 将源点SS向每个有蜥蜴的柱子连边,边权为1。
    2. 将与边界距离不足dd的柱子与汇点TT连边,边权为INFINF
    3. 将拆好的柱子两两连边,边权为a[i][j]a[i][j]
    4. 将直线距离不大于dd的柱子连边,边权为INFINF

    跑一边最大流即可得到能逃出的蜥蜴数量,再用总蜥蜴数量减去得到的答案即可。


    ##代码:

    #include <cstdio>
    #include <iostream>
    #include <queue>
    #include <cstring>
    #define Inf 0x7f
    #define INF 1e9
    using namespace std;
    
    int n,m,d,a[41][41],head[500001],dep[500001],s,t,k,ans,num,sum,x,y;
    char c;
    
    struct edge
    {
    	int next,to,c;
    }e[500001];
    
    void add(int from,int to,int c)
    {
    	k++;
    	e[k].c=c;
    	e[k].to=to;
    	e[k].next=head[from];
    	head[from]=k;
    } 
    
    bool check(int x1,int y1,int x2,int y2)
    {
    	return ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=d*d);
    	//计算两个柱子的直线距离
    	//两边同时开方得 sqrt((x1-x2)^2+(y1-y2)^2)<=d
    	//再利用毕达哥拉斯定理计算
    }
    
    bool bfs()  //分层
    {
    	queue<int> q;
    	q.push(s);
    	memset(dep,Inf,sizeof(dep));
    	dep[s]=0;
    	while (q.size())
    	{
    		int u=q.front();
    		q.pop();
    		for (int i=head[u];i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (dep[v]>dep[u]+1&&e[i].c)  
    			{
    				dep[v]=dep[u]+1;
    				q.push(v);
    			}
    		}
    	} 
    	return (dep[t]<Inf);
    }
    
    int dfs(int u,int low)
    {
    	int lows=0;
    	if (u==t) return low;
    	for (int i=head[u];i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (dep[v]==dep[u]+1&&e[i].c)
    		{
    			lows=dfs(v,min(low,e[i].c));
    			if (!lows) continue;
    			e[i].c-=lows;  //正向边
    			e[(i+1)^1-1].c+=lows;  //反向边
    			return lows;
    		}
    	}
    	return 0;
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&d);
    	s=0;
    	t=n*m*2+1;
    	 //柱子a编号为1~n*m,柱子b编号为n*m+1~2*n*m
    	for (int i=1;i<=n;i++)
    	 for (int j=1;j<=m;j++)
    	 {
    	 	scanf("%1d",&a[i][j]);
    	 	x=(i-1)*m+j;  //计算编号
    	 	add(x,x+n*m,a[i][j]);
    	 	add(x+n*m,x,0);  //柱子a和柱子b连接
    	 	if (i-d<1||i+d>n||j-d<1||j+d>m)  //能跳到边界外
    	 	{
    	 		add(x+n*m,t,INF);
    	 		add(t,x+n*m,0);  //与t相连
    	 	}
    	 }
    	for (int i=1;i<=n;i++)
    	 for (int j=1;j<=m;j++)
    	 {
    	 	cin>>c;
    	 	if (c=='L')  //蜥蜴
    	 	{
    	 		num++;
    	 		x=(i-1)*m+j;
    	 		add(s,x,1);
    	 		add(x,s,0);  //与s相连
    	 	}
    	 }
    	for (int i=1;i<=n;i++)
    	 for (int j=1;j<=m;j++)
    	  for (int k=1;k<=n;k++)
    	   for (int l=1;l<=m;l++)
    	    if (check(i,j,k,l))  //距离不大于d
    	    {
    	    	x=(i-1)*m+j;
    	    	y=(k-1)*m+l;
    	    	add(x+n*m,y,INF);
    	    	add(y,x+n*m,0);
    	    	add(y+n*m,x,INF);
    	    	add(x,y+n*m,0);
    	    }
    	while (bfs())
    	{
    		while (sum=dfs(s,INF))
    		 ans+=sum;
    	}
    	printf("%d\n",num-ans);
    	return 0;
    }
    
  • 相关阅读:
    【Python3之匿名函数及递归】
    【Python3之模块及包的导入】
    :nth-child和:nth-of-type的区别
    JavaScript ES6中export及export default的区别以及import的用法
    vue中npm run dev运行项目不能自动打开浏览器! 以及 webstorm跑vue项目jshint一直提示错误问题的解决方法!
    SEO优化之HTML代码优化最重要的5个标签
    清除浮动小记,兼容Ie6,7
    JavaScript继承基础讲解,原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承
    面向对象JS基础讲解,工厂模式、构造函数模式、原型模式、混合模式、动态原型模式
    纯CSS实现垂直居中的几种方法
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998808.html
Copyright © 2011-2022 走看看