【COCI】 2271 邮递员 暴力(不是树形DP)题解 c++

来源:互联网 发布:数据库的事务是什么 编辑:程序博客网 时间:2024/06/14 22:59

【COCI】邮递员 2271
题目描述
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

分析: 每个点都有一个海拔,而要我们求符合要求的路线中,海拔值最高与最低的值的差最小。根据经验,大部分求最大-最小的题都是通过二分差值来AC的。于是马上得出一个复杂度略(很)高的解法:
1. 二分最大-最小
2. 枚举最小,算出最大
3. dfs||bfs, 验证算出的范围是否能让mirko完成任务(将范围外的点删去)
4. 输出答案
估算时间复杂度:
(log 1e6) //二分
* 1e6 //枚举下界
* 50*50//dfs||bfs
有点大
优化一: 海拔值只有2500种,意味着我们只需要枚举下界2500次,即离散化。有多种方式,但为了简单并且方便,我推荐用STL的set||sort,高效又好写。
复杂度变为:20(log 1e6)* 2500 *2500 = 125000000(明显超时)

优化二:由于房子你必须经过,所以枚举下界和上界时下界小于等于房子的最小值,上界大于等于房子的最大值;(最强力的剪枝,直接快了1s左右)优化三:其实这个有点卡数据,dfs和bfs使用时枚举方向的数组顺序要找好,大家可以试试不同的顺序,也许就AC了呢,楼主就靠这个把时间从1000打到了985,好不容易AC(见代码)。优化四:dfs时判断点能不能走,用vis,在函数外预处理,反正楼主靠此搞了300ms回来。贴AC代码:985ms
#include<cstdio>#include<cstring>#include<set>#include<queue>#include<algorithm>#define maxn 55#define F first#define S secondusing namespace std;set<int>s;int n,dis[maxn][maxn],cnt_k;char map[maxn][maxn];pair<int,int>b,now,k[2505];int U[8]={-1,-1,-1,0,0,1,1,1},z[8]={-1,0,1,-1,1,-1,0,1};bool vis[maxn][maxn];bool check(int u,int v){    return u>0&&u<=n&&v>0&&v<=n&& !vis[u][v];}void get(int &res) {     res=0;    int flag=1;char c;     while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;     while(c>='0'&&c<='9')res=res*10+c-48,c=getchar();     res*=flag; } void dfs(int x,int y){    int u,v;    for(int i=0;i<8;i++)        if(check(u=x+U[i],v=y+z[i]))        {            vis[u][v]=1;            dfs(u,v);        }}bool search(int head,int tail){    memset(vis,-1,sizeof vis);    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            if(dis[i][j]>=head&&dis[i][j]<=tail)                vis[i][j]=0;    dfs(b.F,b.S);    for(int i=0;i<cnt_k;i++)        if(vis[k[i].F][k[i].S]!=1)            return 0;    return 1;}int main(){    int maxh,minh,_minh=2e9,_maxh=0;    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%s",map[i]+1);        for(int j=1;j<=n;j++){            if(map[i][j]=='P')                b=make_pair(i,j);            if(map[i][j]=='K')                k[cnt_k++]=make_pair(i,j);        }    }    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++){            get(dis[i][j]);            s.insert(dis[i][j]);        }    _minh=min(_minh,dis[b.F][b.S]);    _maxh=max(_maxh,dis[b.F][b.S]);    for(int i=0;i<cnt_k;i++){        _minh=min(_minh,dis[k[i].F][k[i].S]);        _maxh=max(_maxh,dis[k[i].F][k[i].S]);    }    set<int>::iterator it=s.end();    it--;    maxh=*it;    minh=*s.begin();    int l=_maxh-_minh,r=*(it)-*(s.begin()),mid;    while(l<r){        bool flag=0;        mid=(l+r)>>1;        for(it=s.begin();it!=s.end();it++)        {            if(*it>_minh || *it+mid<_maxh) continue;            if(search(*it,*it+mid))            {                flag=1;                break;            }        }        if(!flag) l=mid+1;        else r=mid;    }       printf("%d",l);}
原创粉丝点击