• 省选训练赛第4场D题(多米诺骨牌)


    题目来自FZU2163 多米诺骨牌

    Time Limit: 1000 mSec    Memory Limit : 32768 KB

     Problem Description

    Vasya非常喜欢排多米诺骨牌。他已经厌倦了普通的多米诺骨牌,所以他用不同高度的多米诺骨牌。他从左边到右边,把n个多米诺骨牌沿一个轴放在桌子上。每个多米诺骨牌垂直于该轴,使该轴穿过其底部的中心。第i个多米诺骨牌具有坐标xi与高度hi。如今Vasya想要知道,对于每个多米诺骨牌假设他推倒的话,右側会有多少个多米诺骨牌也会倒下。

    想想看,一个多米诺倒下,假设它严格的触动右側的多米诺骨牌,被触碰的也会倒下。换句话说,假设多米诺骨牌(初始坐标x和高度h)倒下,会导致全部在[ X + 1,x + H - 1]范围内的多米诺骨牌倒下。

     Input

    输入有多组測试数据,处理到文件结尾。

    每组測试数据第一行包括整数n(1≤N≤10^5),这是多米诺骨牌的数量。然后n行,每行包括两个整数xi与hi(-10^8≤xi≤10^8 ,2 ≤hi≤108),xi表示多米诺骨牌的坐标和hi表示多米诺骨牌的高度。没有两个多米诺骨牌在同一个坐标点上。

     Output

    对于每组数据输出一行,包括n个空格分隔的数Zi - 表示倒下的多米诺骨牌数量,假设Vasya推第i个多米诺骨牌(包括多米诺骨牌本身)。

     Sample Input

    4
    16 5
    20 5
    10 10 18 2
    3
    6 7
    2 9
    -6 10

     Sample Output

    3 1 4 1
    1 2 3

    第一次比赛中出现中文题目,真心认为高兴啊,无需百度翻译了……

    这题目在比赛的时候我并没有思路,最后也没有做这题,赛后才思考这到题,一開始的想法就是动态规划,认为是在可接触范围内的

    从后面開始,dp[i]=max{1+dp[x]),x为i~i+h-1中有多米骨牌的坐标。

    可是这样一想,dp开的数组太大了(10^8),且这 dp效率明显不高啊!由于这个范围内着到有坐标,明显会超时。

    后来换一种思维来看,我们先依照横坐标排序,并又一次编号,能推倒的多米诺牌的最后一个,肯定是不能推倒的那个的前一个,所以找到不能推倒的,再回溯回去。

    这样非常自然,就会使用栈结构了,我们用排序后的第一张牌压入栈,我们按新编号第二张牌開始去遍历,当前牌是栈顶部元素无法接触的时候,那么栈顶部能推倒的是这张牌的新序号减上栈顶部的新序号,而且非常有可能栈中其它元素能触碰到这张牌(也依照刚刚的推断方法,能否触碰到当前牌,能则继续pop)。当能触碰到,则继续压入栈。

    即是:仅仅在能够确定到不能触碰的时候才看開始考虑之前的牌!

    所以,我们要引入一张无法触碰的,x坐标在无穷远(1<<30),这样,每一个牌肯定会找到无法触碰的牌(最坏情况就是找到引入的牌)

    我写了两个代码,一个是以类的形式来写,还有一个是直接用数组,两者来说,第一个比較好理解。

    类的形式:

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<stack>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n;
    class GP{
    public:
        int id;
        int s_id;  // sort id
        int x;     //横坐标
        int h;     //高度
    
        GP(){};
    
        bool operator <(const GP &g)const{
    
           return this->x<g.x;
        }
        void operator =(const GP &g){
            this->id=g.id;
            this->s_id=g.s_id;
            this->x=g.x;
            this->h=g.h;
        }
    
    };
    vector<GP> v;   //骨牌
    stack<GP>  stk; //栈结构
    int ans[100005];//结果数组
    int main(){
       
        int i;
    
        while(scanf("%d",&n)!=EOF){
                v.clear();
                while(!stk.empty()){stk.pop();}
                v.resize(n+1);
            for(i=0;i<n;i++){
                v[i].id=i;
                scanf("%d%d",&v[i].x,&v[i].h);
    
    
            }
            v[n].x=200000001; //无穷远
            v[n].h=0;
            v[n].s_id=n;
            sort(v.begin(),v.end());
            for(i=0;i<n;i++){
                v[i].s_id=i;
    
            }
            stk.push(v[0]);
            GP tmp;
            for(i=1;i<=n;i++){
    
    
                while(!stk.empty()&&stk.top().x+stk.top().h-1<v[i].x){  //直到无法触及的多米诺
                    tmp=stk.top();
                    stk.pop();
                 //   cout<<tmp.x<<" "<<tmp.s_id<<" "<<v[i].s_id<<endl;
                    ans[tmp.id]=v[i].s_id-tmp.s_id;
    
                }
                stk.push(v[i]);
    
            }
    
    
    
            for(i=0;i<n-1;i++){
    
                printf("%d ",ans[i]);
            }
            printf("%d
    ",ans[n-1]);
    
    
    
        }
        return 0;
    
    }

    数组形式:

    #include<iostream>
    #include<stack>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define N 100005
    int id[N],x[N],h[N],ans[N];
    bool CMP (int a,int b){
    
    
        return x[a]<x[b];
    
    }
    stack<int> stk;
    int main(){
       int n,i;
      
       while(scanf("%d",&n)!=EOF){
    
            while(!stk.empty()) stk.pop();
            for(i=0;i<n;i++){
    
                scanf("%d%d",x+i,h+i);
                id[i]=i;
    
            }
            x[n]=1<<30;
            id[n]=n;
    
    
            sort(id,id+n,CMP);
    
    
            stk.push(0);
            for(i=1;i<=n;i++){
    
                while(!stk.empty()&&x[id[stk.top()]]+h[id[stk.top()]]-1<x[id[i]]){  //无法触碰的多米诺
                    int j=stk.top();
                    stk.pop();
                    ans[id[j]]=i-j;
    
                }
    
                stk.push(i);
    
            }
            for(i=0;i<n-1;i++){
                printf("%d ",ans[i]);
    
            }
            printf("%d
    ",ans[n-1]);
    
    
       }
    
      return 0;
    }
    



  • 相关阅读:
    汇编代码中db,dw,dd的区别
    利用汇编详解栈结构
    80X86指令总结
    【原创】自己动手写的一个查看函数API地址的小工具
    【初学破解】暴力破解绕过程序认证
    OD基本汇编指令
    排序算法
    数据聚类算法-K-means算法
    数据预测算法-ARIMA预测
    数据预测算法-指数平滑法-1
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4000348.html
Copyright © 2020-2023  润新知