题目描述

Mirko在一个山镇找到了一份邮递员的工作。这个镇可以看作一个N*N的矩形。每个区域可能是以下之一:房子K,邮政局P,草地 ‘.’。每个区域都有一个海拔。

每天早上,Mirko要送信给镇上所有的家庭。他从邮局P处开始,可以向8个方向到相邻的一个区域,当他送完最后一份信后,他必须回到邮局。

现在用Mirko走过的路线中海拔最高点和最低点之差来表示他的疲劳程度。帮他计算出送出所有的信最少的疲劳值。

输入

第一行包含整数N(2<=N<=50)。接下来的N行表示矩形。P只出现一次,而K最少出现一次。

接下来N行每行包含N个正整数,表示相应区域的海拔。均小于1000000.

输出

单独的一行,一个整数,表示最小的疲劳值。

样例输入

2

P.

.K

2 1

3 2

样例输出

0

多么有(wei)趣(suo)的一道题啊!!!!!!!!!

多么有(wei)趣(suo)的一道题啊!!!!!!!!!

多么有(wei)趣(suo)的一道题啊!!!!!!!!!

(重要的事情说三遍)

题解很多人都yy到了——二分疲劳度,枚举最小海拔,搜索验证

但给我的结果是

TLE 2000ms+

超时代码如下:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;
struct node{
int x,y;
}p[2501];
int height[51][51];
int map[51][51];
int n,cnt;
set<int>h;
int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
void getmap()
{
int i,j;
char c[51];
for(i=1;i<=n;i++)
{
scanf("%s",c+1);
for(j=1;j<=n;j++)
if(c[j]!='.')p[++cnt].x=i,p[cnt].y=j;
}
}
int u[8]={-1,-1,-1,0,0,1,1,1},z[8]={-1,0,1,-1,1,-1,0,1};
void bfs()
{
queue<int>Q[2];
Q[0].push(p[1].x),Q[1].push(p[1].y);
if(!map[p[1].x][p[1].y])map[p[1].x][p[1].y]=1;
while(!Q[0].empty())
{
int x=Q[0].front(),y=Q[1].front();Q[0].pop(),Q[1].pop();
for(int i=0;i<8;i++)
if(x+u[i]>0&&x+u[i]<=n&&y+z[i]>0&&y+z[i]<=n&&!map[x+u[i]][y+z[i]])
{
map[x+u[i]][y+z[i]]=1;
Q[0].push(x+u[i]),Q[1].push(y+z[i]);
}
}
}
bool work(int minh,int maxh)
{
int i,j;
memset(map,-1,sizeof map);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(height[i][j]>=minh&&height[i][j]<=maxh)
map[i][j]=0;
bfs();
for(i=1;i<=cnt;i++)if(map[p[i].x][p[i].y]!=1)return 0;
return 1;
}
int main()
{
int i,j;
n=getint();
getmap();
set<int>::iterator iter;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
h.insert(height[i][j]=getint());
int l=0,r=1000000;
while(l<r)
{
bool p=0;
int mid=(l+r)>>1;
for(iter=h.begin();iter!=h.end();iter++)
if(work(*iter,*iter+mid)){p=1;break;}
if(p)r=mid;
else l=mid+1;
}
printf("%d",l);
}

orz=orz=orz=orz

过不了,正解也yy不到,那就只有拿起菜刀,剪枝去

拿着菜刀,细看每一段代码,刀尖落在了这一段:

for(iter=h.begin();iter!=h.end();iter++)
if(work(*iter,*iter+mid)){p=1;break;}

在枚举的过程中,总会枚举到一些最小海拔,大于了邮局或住宅的海拔,

或最大海拔,小于了邮局或住宅的海拔

岂能容忍?剪!!

设minh与maxh为停留点的最小最大海拔

更改为:

for(iter=h.begin();iter!=h.end();iter++)
if(*iter<=minh&&*iter+mid>=maxh)
if(work(*iter,*iter+mid))
{p=1;break;}

交上去 TLE 1108ms

剪了不少!

又挑到了一段:

int l=0,r=1000000;

二分范围能不能剪呢?

我猛然发现,最小疲劳一定不小于maxh-minh,而最大疲劳一定小于等于整张地图的最高海拔减最低海拔

改了之后交上去 TLE 1009ms

加油!努力!还差9ms

挑来挑去,还是在验证中的BFS中入手吧

我验证的方法是将不在海拔范围内的点标记后,从一号停留点开始遍历全图,看看每一个停留点是否被遍历到

等等,既然是遍历,没有其他最短路或极值的操作,那DFS的访问次数与BFS是一样的,而且BFS的系数还比较大

欣欣然将BFS改为DFS

怀着鸡冻的心情,我交了代码

AC 877ms

23333333333333333333333333333333333333333~~~~~~~~~~~~~~~~

功夫不负有心人,在精(sang)雕(xin)细(bing)琢(kuang)的剪枝下,AC了!!!!!

代码如下:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;
struct node{
int x,y;
}p[2501];
int height[51][51];
int map[51][51];
int n,cnt;
set<int>h;
int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
void getmap()
{
int i,j;
char c[51];
for(i=1;i<=n;i++)
{
scanf("%s",c+1);
for(j=1;j<=n;j++)
if(c[j]!='.')p[++cnt].x=i,p[cnt].y=j;
}
}
int u[8]={-1,-1,-1,0,0,1,1,1},z[8]={-1,0,1,-1,1,-1,0,1};
void bfs()
{
queue<int>Q[2];
Q[0].push(p[1].x),Q[1].push(p[1].y);
if(!map[p[1].x][p[1].y])map[p[1].x][p[1].y]=1;
while(!Q[0].empty())
{
int x=Q[0].front(),y=Q[1].front();Q[0].pop(),Q[1].pop();
for(int i=0;i<8;i++)
if(x+u[i]>0&&x+u[i]<=n&&y+z[i]>0&&y+z[i]<=n&&!map[x+u[i]][y+z[i]])
{
map[x+u[i]][y+z[i]]=1;
Q[0].push(x+u[i]),Q[1].push(y+z[i]);
}
}
}
void dfs(int x,int y)
{
int i;
for(i=0;i<8;i++)
if(!map[x+u[i]][y+z[i]]&&x+u[i]>0&&x+u[i]<=n&&y+z[i]>0&&y+z[i]<=n)
{
map[x+u[i]][y+z[i]]=1;
dfs(x+u[i],y+z[i]);
}
}
bool work(int minh,int maxh)
{
int i,j;
memset(map,-1,sizeof map);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(height[i][j]>=minh&&height[i][j]<=maxh)
map[i][j]=0;
//bfs();
dfs(p[1].x,p[1].y);
for(i=1;i<=cnt;i++)if(map[p[i].x][p[i].y]!=1)return 0;
return 1;
}
int main()
{
int i,j,minh=1<<30,maxh=0,k=1,_minh=1<<30,_maxh=0;
n=getint();
getmap();
set<int>::iterator iter;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
h.insert(height[i][j]=getint());
if(p[k].x==i&&p[k].y==j)
{
k++;
minh=min(minh,height[i][j]);
maxh=max(maxh,height[i][j]);
}
_minh=min(_minh,height[i][j]);
_maxh=max(_maxh,height[i][j]);
}
int l=maxh-minh,r=_maxh-_minh;
while(l<r)
{
bool p=0;
int mid=(l+r)>>1;
for(iter=h.begin();iter!=h.end();iter++)
if(*iter<=minh&&*iter+mid>=maxh)
if(work(*iter,*iter+mid))
{p=1;break;}
if(p)r=mid;
else l=mid+1;
}
printf("%d",l);
}

CQBZOJ 邮递员(直播剪枝技巧)的更多相关文章

  1. 深搜的剪枝技巧(三)——Sticks(可行性剪枝、上下界剪枝、最优性剪枝)

    小木棍(最优性剪枝.可行性剪枝) 一.问题描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,已知每段的长都不超过 50 .现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍 ...

  2. 一本通例题埃及分数—题解&&深搜的剪枝技巧总结

    一.简述: 众所周知,深搜(深度优先搜索)的时间复杂度在不加任何优化的情况下是非常慢的,一般都是指数级别的时间复杂度,在题目严格的时间限制下难以通过.所以大多数搜索算法都需要优化.形象地看,搜索的优化 ...

  3. hdoj1010 奇偶剪枝+DFS

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  4. POJ 2531 深搜剪枝

    题意:全局最大割. 分析:有相应的算法,数据量很小,可以枚举源点,汇点,最大流. 这里用DFS,状态定义:分成两个集合,刚开始S集合全部点,然后一个一个放,这是一个回溯的过程. 没剪枝也过了. 剪枝技 ...

  5. 剪枝的定义&&hdu1010

    半年前在POJ上遇到过一次剪枝的题目,那时觉得剪枝好神秘...今天在网上查了半天资料,终于还是摸索到了一点知识,但是相关资料并不多,在我看来,剪枝是技巧,而不是方法,也就是说,可能一点实用的小技巧,让 ...

  6. poj1011(DFS+剪枝)

    题目链接:https://vjudge.net/problem/POJ-1011 题意:给定n(<=64)条木棍的长度(<=50),将这些木棍刚好拼成长度一样的若干条木棍,求拼出的可能的最 ...

  7. poj1011 Sticks (dfs剪枝)

    [题目描述] George took sticks of the same length and cut them randomly until all parts became at most 50 ...

  8. LeetCode37 使用回溯算法实现解数独,详解剪枝优化

    本文始发于个人公众号:TechFlow,原创不易,求个关注 数独是一个老少咸宜的益智游戏,一直有很多拥趸.但是有没有想过,数独游戏是怎么创造出来的呢?当然我们可以每一关都人工设置,但是显然这工作量非常 ...

  9. noip2004提高组题解

    这次有两道题以前已经做过了,所以分数什么的也没有意义了.发现这年的难度设置极不靠谱,前三题都比较简单,最后一题太难,不知道出题人怎么想的. 第一题:储蓄计划 模拟. 第二题:合并果子 贪心.每次选最小 ...

随机推荐

  1. vue-learning:15 - js - data

    data data属性是一个对象,存放最纯粹的数据,这些数据可以在模板template.计算属性computed.方法methods.监听器watch.过滤器filters.生命周期函数中使用,并且可 ...

  2. JQuery仿购物网站放大镜特效所遇问题及思考

    JQuery仿购物网站放大镜特效所遇问题及思考 先贴下效果图,然后描述起来也就不会不知道我在说什么了. 我碰到的问题一: 一开始我自己总结了是因为两个小原因导致的①使用了mouseover,mouse ...

  3. dotnet 通过 WMI 获取设备厂商

    本文告诉大家如何通过 WMI 获取设备厂商 通过 Win32_ComputerSystem 可以获取电脑系统信息 通过下面代码可以获取 机器型号 和 制造厂商 var mc = "Win32 ...

  4. 创意app1

      app名称: 与我相似的人 app目的: 旨在通过云匹配,搜索到与自己类似爱好或者性格的人用户相似的内容:衣服品牌鞋子手机笔记本键盘鼠标相机刮胡刀自行车工作  说明: 现有的格局 百度贴吧是面向多 ...

  5. Qt StyleSheet皮肤css源码(黑色,超详细) 乌合之众 good

    使用方式如下 //设置皮肤样式 static void SetStyle(const QString &styleName) { QFile file(QString(":/imag ...

  6. JAVA8学习——深入浅出Lambda表达式(学习过程)

    JAVA8学习--深入浅出Lambda表达式(学习过程) lambda表达式: 我们为什么要用lambda表达式 在JAVA中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法. 在 ...

  7. 如何基于TencentOS tiny,快速打造属于自己的IoT小应用?

    导语 | 近日,云+社区技术沙龙“腾讯开源技术”圆满落幕.本次沙龙邀请了多位腾讯技术专家,围绕腾讯开源与众多开发者进行探讨,深度揭秘了腾讯开源项目TencentOS tiny.TubeMQ.Kona  ...

  8. 给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。-----力扣

    给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积. 示例: 输入: [1 ...

  9. 【题解】[HAOI2018]染色(NTT+容斥/二项式反演)

    [题解][HAOI2018]染色(NTT+容斥/二项式反演) 可以直接写出式子: \[ f(x)={m \choose x}n!{(\dfrac 1 {(Sx)!})}^x(m-x)^{n-Sx}\d ...

  10. 洛谷$P$3160 局部极小值 $[CQOI2012]$ 状压$dp$

    正解:状压$dp$ 解题报告: 传送门! 什么神仙题昂,,,反正我是没有想到$dp$的呢$kk$,,,还是太菜了$QAQ$ 首先看数据范围,一个4×7的方格,不难想到最多有8个局部极小值,过于显然懒得 ...