CQBZOJ 邮递员(直播剪枝技巧)
题目描述
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 邮递员(直播剪枝技巧)的更多相关文章
- 深搜的剪枝技巧(三)——Sticks(可行性剪枝、上下界剪枝、最优性剪枝)
小木棍(最优性剪枝.可行性剪枝) 一.问题描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,已知每段的长都不超过 50 .现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍 ...
- 一本通例题埃及分数—题解&&深搜的剪枝技巧总结
一.简述: 众所周知,深搜(深度优先搜索)的时间复杂度在不加任何优化的情况下是非常慢的,一般都是指数级别的时间复杂度,在题目严格的时间限制下难以通过.所以大多数搜索算法都需要优化.形象地看,搜索的优化 ...
- hdoj1010 奇偶剪枝+DFS
Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Othe ...
- POJ 2531 深搜剪枝
题意:全局最大割. 分析:有相应的算法,数据量很小,可以枚举源点,汇点,最大流. 这里用DFS,状态定义:分成两个集合,刚开始S集合全部点,然后一个一个放,这是一个回溯的过程. 没剪枝也过了. 剪枝技 ...
- 剪枝的定义&&hdu1010
半年前在POJ上遇到过一次剪枝的题目,那时觉得剪枝好神秘...今天在网上查了半天资料,终于还是摸索到了一点知识,但是相关资料并不多,在我看来,剪枝是技巧,而不是方法,也就是说,可能一点实用的小技巧,让 ...
- poj1011(DFS+剪枝)
题目链接:https://vjudge.net/problem/POJ-1011 题意:给定n(<=64)条木棍的长度(<=50),将这些木棍刚好拼成长度一样的若干条木棍,求拼出的可能的最 ...
- poj1011 Sticks (dfs剪枝)
[题目描述] George took sticks of the same length and cut them randomly until all parts became at most 50 ...
- LeetCode37 使用回溯算法实现解数独,详解剪枝优化
本文始发于个人公众号:TechFlow,原创不易,求个关注 数独是一个老少咸宜的益智游戏,一直有很多拥趸.但是有没有想过,数独游戏是怎么创造出来的呢?当然我们可以每一关都人工设置,但是显然这工作量非常 ...
- noip2004提高组题解
这次有两道题以前已经做过了,所以分数什么的也没有意义了.发现这年的难度设置极不靠谱,前三题都比较简单,最后一题太难,不知道出题人怎么想的. 第一题:储蓄计划 模拟. 第二题:合并果子 贪心.每次选最小 ...
随机推荐
- dotnet 将文件删除到回收站
默认删除文件的时候 File.Delete 是将文件永久删除,如果是一些文档,建议删除到回收站,这样用户可以自己还原 通过 SHFileOperation 可以将文件放在回收站 本文提供的方法暂时只能 ...
- 2018 CCPC 吉林站 H Lovers
2018 CCPC 吉林站 H Lovers 传送门:https://www.spoj.com/problems/LIS2/en/ 题意: q次操作 1.将第l~r个数的左边和和右边都加上一个数d, ...
- C++Review7_STL、容器、迭代器
我之前的博文中有专门的5篇整理并介绍了STL的概念: STL1——整体介绍:https://www.cnblogs.com/grooovvve/p/10467794.html STL2——泛型编程(模 ...
- IntelliJ IDEA+springboot+jdbctemplet+easyui+maven+oracle搭建简易开发框架(一)
前言: 这两天为了巩固easyui的各个控件用法,搭建了一个简易的框架用于开发,大家可以用来参考,如果发现文章中有哪些不正确不合理的地方,也请各位不吝赐教,感激不尽.文章最下面有源码,可以用于参考.整 ...
- 神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程(二)
开心一刻 一头母牛在吃草,突然一头公牛从远处狂奔而来说:“快跑啊!!楼主来了!” 母牛说:“楼主来了关我屁事啊?” 公牛急忙说:“楼主吹牛逼呀!” 母牛大惊,拔腿就跑,边跑边问:“你是公牛你怕什么啊? ...
- 机器学习之路--Matplotlib
1.绘制折线图 在pandas里面有一种数据类型为datatime ,可以将不规范的日期改为:xxxx-xx-xx import pandas as pd import numpy as np a = ...
- 基于 Blazui 的 Markdown 编辑器 Blazui.Markdown 尝鲜
想做一个文档平台用来存放和展示 Blazui 的文档,然后基于 Markdown 写文档,但缺一个好用的 Blazor Markdown 编辑器,所以就顺便写一个了,功能上基本抄的 https://p ...
- yarn详细入门教程(转载)
简介Yarn 是 Facebook, Google, Exponent 和 Tilde 开发的一款新的 JavaScript 包管理工具.就像我们可以从官方文档了解那样,它的目的是解决这些团队使用 n ...
- c++中减字符0的作用(转)
在刷OJ题的时候遇到要读取“2013-3-1”形式的日期然后计算这个日期是该年的第几天, 显然我们读取的是字符串,但是计算第几天却要整型数来计算,这是这个问题的难点,下面是解决这个问题的代码: int ...
- JavaScript系列之回调函数callback
JavaScript系列之回调函数callback JavaScript回调函数的使用是很常见的,引用官方回调函数的定义: A callback is a function that is passe ...