• Uva 1579 Matryoshkas


    这道题应该是dp(有点空洞)我们想,f(i)表示前i个套娃合并成多个套娃组所应操作的最小次数

    f(i)=min(f(j)+dp(j+1,i));

    这里自然的引出了dp(j+1,i)什么是dp(j+1,i)呢?

    dp(j+1,i)合并成一个套娃所拥有的最小代价。

    这里又不自然的dp(j+1,i)=min{dp(j+1,k)+dp(k,i)+操作数}

    那么操作数又是什么呢,

     对于要合并的两个区间[l,k]&[k+1,r],最后一步把他们合并的费用是多少呢?假设m1=min[l,k],m2=min[k+1,r],则不用打开的套娃数为这个区间中小于max(m1,m2)的数的个数。 
     问题完美解决。
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 500+10
    #define inf 0x3fffffff
    using namespace std;
    int a[N],mx[N][N],mn[N][N],p[N][N];
    int n;
    int f1[N][N],f2[N];
    struct node{
        int x,id;
        inline bool operator < (const node & a)const{return x<a.x;}
    };
    void init()
    {
        memset(mx,0,sizeof(mx));memset(mn,63,sizeof(mn));
        memset(p,0,sizeof(p));
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)mn[i][i]=mx[i][i]=a[i],p[i][i]=1;
        int flag;
        for(int i=n;i>=1;i--)
            for(int j=i+1;j<=n;j++)
            {
                mx[i][j]=max(mx[i][j-1],a[j]);
                mn[i][j]=min(mn[i][j-1],a[j]);
                flag=1;
                for(int k=j-1;k>=i;k--)
                {
                    if(a[k]==a[j]){flag=0;break;}
                }
                if(flag&&p[i][j-1])p[i][j]=1;
            }
    //             for(int i=1;i<=n;i++)
    //         for(int j=1;j<=n;j++)
    //         {
    //             printf("%d %d %d
    ",i,j,p[i][j]);
    //        }
    }
    int dp(int x,int y)
    {
        if(f1[x][y]<10000) return f1[x][y];
        if(x==y){return f1[x][y]=0;}
        int num;
        node t[N];
        for(int i=x;i<=y;i++)t[i-x+1].x=a[i],t[i-x+1].id=i;
        sort(t+1,t+1+y-x+1);
        for(int i=x;i<y;i++)
        {
            int mm=max(mn[x][i],mn[i+1][y]);
            num=0;
            for(int j=1;j<=y-x+1;j++)
            {
                if(t[j].x==mm) break;
                if(t[j].x<mm) num++;
            }
            num=y-x+1-num;
            f1[x][y]=min(f1[x][y],dp(x,i)+dp(i+1,y)+num);
        }
        return f1[x][y];
    }
    void slove()
    {
        memset(f1,63,sizeof(f1));
        memset(f2,63,sizeof(f2));
    //    for(int i=1;i<=n;i++)
    //         for(int j=i;j<=n;j++)
    //     {
    //         if(mx[i][j]==j-i+1&&p[i][j]) 
    //             printf("%d %d %d
    ",i,j,dp(i,j));
    //     }
        f2[0]=0;
        for(int i=1;i<=n;i++)
            for(int j=0;j<i;j++)
        {
    
            if(p[j+1][i]&&i-j==mx[j+1][i])
            f2[i]=min(f2[i],f2[j]+dp(j+1,i));
    //        printf("%d %d %d
    ",j+1,i,dp(j+1,i));
        }
        if(f2[n]>10000)printf("impossible
    ");
        else printf("%d
    ",f2[n]);
    
    }
    int main()
    {
        while(scanf("%d",&n)==1)
        {
            init();
            slove();
        }
        return 0;
    }

    p[i][j]表示i——j这段区间是否有重复的元素,小技巧p[i][j]=(p[i][j-1]&&a[j]!=任何i————j-1的数)

  • 相关阅读:
    io系列之常用流一
    C++ 函数参数的默认值
    C++ 函数匹配和作用域声明
    c++ vector 迭代器 demo
    C++ 函数重载和匹配
    C++函数重载和const
    C++函数重载
    iOS开源项目
    Linux系统/网络 笔记
    IO五种模式
  • 原文地址:https://www.cnblogs.com/star-eternal/p/7754277.html
Copyright © 2020-2023  润新知