zoukankan      html  css  js  c++  java
  • 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);
    }
  • 相关阅读:
    1012 The Best Rank (25 分)(排序)
    1011. World Cup Betting (20)(查找元素)
    1009 Product of Polynomials (25 分)(模拟)
    1008 Elevator (20 分)(数学问题)
    1006 Sign In and Sign Out (25 分)(查找元素)
    1005 Spell It Right (20 分)(字符串处理)
    Kafka Connect 出现ERROR Failed to flush WorkerSourceTask{id=local-file-source-0}, timed out while wait
    flume、kafka、avro组成的消息系统
    Java23种设计模式总结【转载】
    Java编程 思维导图
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12002545.html
Copyright © 2011-2022 走看看