题目描述

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. 【38.63%】【hdu 3047】Zjnu Stadium

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s) ...

  2. 网摘-获取屏幕dc并且将其画面显示在窗体中

    获取屏幕dc并且将其画面显示在窗体中 HWND hWnd = ::GetDesktopWindow();//获得屏幕的HWND. HDC hScreenDC = ::GetDC(hWnd);   // ...

  3. jedis 连接池工具类

    maven <properties> <jedis.version>3.0.1</jedis.version> <junit.verion>4.12&l ...

  4. $BZOJ$2818 $gcd$ 莫比乌斯反演/欧拉函数

    正解:莫比乌斯反演/欧拉函数 解题报告: 传送门$QwQ$ 一步非常显然的变形,原式=$\sum_{d=1,d\in prim}^{n}\sum_{i=1}^{n}\sum_{j=1}^{n}[gcd ...

  5. java如何实现在线支付讲解

    转载:https://www.cnblogs.com/haorun/p/6728466.html 国内电子商务系统实现的基本流程如下: 客户在系统内下订单 -> 系统根据订单生成支付宝接口url ...

  6. C# 添加文本、图片到PDF文档(基于Spire.Cloud.PDF.SDK)

    Spire.Cloud.PDF.SDK提供了接口PdfTextApi及PdfImagesApi用于添加文本和图片到PDF文档,添加文本时,可格式化文本样式,包括文本字体类型.字号.字体样式.文本颜色. ...

  7. 「Luogu P1210」回文检测 解题报告

    题面 这是一道诡异的黄题 居然让你求一串吧啦吧啦的东西中 字母(大小写)最长的回文串的长度,还要输出完整的串 吐血 思路: 保持淡定,我们啥都不会,就会Manacher,那就用Manacher大法! ...

  8. k8s-自动安装

    操作环境: centos7.3 node102-master-192.168.100.102 node103-node1-192.168.100.103 node104-node2-192.168.1 ...

  9. MyBatis项目实战 快速将MySQL转换成Oracle语句

    一.前言 因项目需求,小编要将项目从mysql迁移到oracle中 ~ 之前已经完成 数据迁移 (https://zhengqing.blog.csdn.net/article/details/103 ...

  10. ArcEngine 里面的日期

    问题: 将自己做的GIS系统放到其他系统上的时候发现用 IQueryFilter 进行时间查询的时候报错,原来的系统没有这个问题. 原因: 后来调试代码发现查询的时间里面有中文,显示格式 " ...