analysis

来源:互联网 发布:javascript冒泡排序 编辑:程序博客网 时间:2024/04/19 11:20

analysis

Time Limits: 1000 ms Memory Limits: 128000 KB

Description
给你N个数字,将其分成若干子序列,每个序列都必须是递增或递减的.
希望子序列的数量越少越好。

Input
本题有多组数据
对于每组数据,第一行一个整数N
第二行N个整数Ai.

Output
对于每组数据,输出最少的个数

Sample Input

1531 3 2

Sample Output

12

Hint
数据范围
N<=50
保证Ai中的数字不重复,且0<=Ai<=200
每个输入文件中不超过10组数据
提示
对于Pascal选手,推荐使用seekeof判断文件结束

》》题目感知:题目太码农,解法太玄学!!

总而言之,题目出得有点过于坑


解题思路

主要算法就是搜索,直接暴力,枚举(或二分)答案,然后再深搜迭代加深。

设tot1表示为降序列的个数,tot2表示为升序列的个数,Ui表示为第i个生序列的队首,Di表示为第i个降序列的队首。

有如下几种操作:

  1. 若tot2=0,新开一个U存入当前的数,深搜一遍;
  2. 若tot1=0,新开一个D存入当前的数,深搜一遍;
  3. 若tot1>0且存在Di>当前的数,让当前的数存入符合条件的Di中最小的序列,深搜一遍;
  4. 若tot2>0且存在Ui<当前的数,让当前的数存入符合条件的Ui中最大的序列,深搜一遍;
  5. 若tot1>0但不存在Di>当前的数,新开一个D存入当前的数,深搜一遍;
  6. 若tot2>0但不存在Ui<当前的数,新开一个U存入当前的数,深搜一遍。

注意,一定要按照这种顺序(除非你打得十分优美),否则会TLE,至于为什么,我也不知道。同时,注意一下输入,非常坑。这就是我为什么说“》》题目感知:题目太码农,解法太玄学!!”的原因了。

Codes:

#include<cstdio>#include<cstring>#include<cmath>#define fo(i,x,y) for(int i=x;i<=y;i++)using namespace std;int n,a[51],mid,tot1,tot2,U[51],D[51];char num;bool q;void can(int);int main(){    for(;;)//相当于while(1)    {        num=getchar();        if(num<'0' || num>'9')break;        int x=num-'0';        for(;;)        {            num=getchar();            if(num<'0' || num>'9')break;            x+=x*9+(num-'0');        }        fo(i,1,x)scanf("%d",&a[i]);        scanf("\n");        n=x;        int l=1,r=floor(sqrt(n)),ans=r;/*枚举到√n即可,易证*/        while(l<=r) //二分        {            mid=(l+r)>>1;            q=0;            tot1=tot2=0;            can(1);            if(q)            {                r=mid-1;                ans=mid;            }else{                l=mid+1;            }        }        printf("%d\n",ans);    }   }void can(int w)/*搜索顺序很关键*/{    bool p=0,o=0;    int wz,s,z;    if(tot1+tot2>mid)return;    if(w>n){q=1;return;}    if(tot2==0)    {        U[++tot2]=a[w];        can(w+1);if(q)return;        tot2--;/*这里一定不要丢掉*/    }    if(tot1==0)    {        D[++tot1]=a[w];        can(w+1);if(q)return;        tot1--;/*这里一定不要丢掉*/    }    if(tot1>0)    {        z=0x7fffffff;        for(int i=1;i<=tot1;i++)        {            if(D[i]>a[w] && D[i]<z)            {                z=D[i];wz=i;            }        }        if(z<0x7fffffff)        {            s=D[wz];            D[wz]=a[w];            can(w+1);if(q)return;            D[wz]=s;/*这里一定不要丢掉*/        }else p=1;    }    if(tot2>0)    {        z=-1;        for(int i=1;i<=tot2;i++)        {            if(a[w]>U[i] && U[i]>z)            {                z=U[i];wz=i;            }        }        if(z>-1)        {            s=U[wz];            U[wz]=a[w];            can(w+1);if(q)return;            U[wz]=s;/*这里一定不要丢掉*/        }else o=1;    }    if(p)    {        D[++tot1]=a[w];        can(w+1);if(q)return;        tot1--; /*这里一定不要丢掉*/    }    if(o)    {        U[++tot2]=a[w];        can(w+1);if(q)return;        tot2--;/*这里一定不要丢掉*/    }}

这些“/这里一定不要丢掉/”,重要的事说三遍,这里说六遍,脑补一下

1 0
原创粉丝点击