zoukankan      html  css  js  c++  java
  • 【线性dp】【区间dp】

    1>尼克的任务

    额一道挺水的题,愣是做了几个小时

    动态规划大致的思路还是找一个转移

    换个词就是影响

     

    我们可以明显看出本题的规则:

    空暇时,一遇到任务必须挑一个接

    1-n时间内最大空暇时间

    所以将任务排序是必要的,两个关键字

     

    再来想象一下当我做到第i个任务时,我在st[i]-st[i]+t[i]-1)时必然在工作

    那么1-(st[i]+t[i]-1)的区间内,

    是我上一个任务的f[j]和与j任务之间的时间空暇决定的

    则现在的问题是,找出所以合法j任务,然后加上st[i]-st[j]-t[j]

     

    合法的j任务应该满足什么要求呢

    st[i]之前已经完成,但是又不能已经完成了太久

    这个不能完成太久的条件,其实正着推最容易,

    就是j+1任务往后数,最先开始的那个就是,

    所以我们需要一个新数组,预处理这个最先开始

     

    当然其实我可以不要这个数组

    只要每个当前任务点,去更新后面的任务点

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cstring> 
    using namespace std;
    int m,n;
    const int N=10003;
    struct node
    {
        int st,ed;//这里是左闭合,右开 
        bool operator < (const node & o) const
        {
            if(st!=o.st) return st<o.st;
            else return ed<o.ed;
        }
    }d[N];
    int f[N];
    
    int main()
    {
        scanf("%d%d",&m,&n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&d[i].st ,&d[i].ed ),d[i].ed +=d[i].st ;
        d[++n].st =m+1,d[n].ed =m+1;
        sort(d+1,d+n);
        
        memset(f,-1,sizeof(f));
        int i=2;
        f[1]=d[1].st -1;
        while(i<n && d[i].st ==d[1].st ) f[i++]=f[1];
        
        for(i=1;i<n;i++)
        {
            if(f[i]==-1) continue;
            int nx=i+1;
            while(nx<n && d[nx].st <d[i].ed ) nx++;
            
            //printf("%d %d
    ",d[i].st ,d[i].ed );
            int dis=d[nx].st -d[i].ed ;
            for(int j=nx;j<=n && d[j].st ==d[nx].st ;j++)
            {
                f[j]=max(f[i]+dis,f[j]);
                //,printf(" %d %d %d
    ",d[j].st ,d[j].ed ,f[j]);
                //if(d[j].st ==9994) printf("%d %d %d
    ",i,f[i],dis);
            }
        }
        
        printf("%d
    ",f[n]);
        return 0;
    } 
    //倒序做
    //为什么? 
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm> 
    #include<vector>
    using namespace std;
    int m,n;
    const int N=10003;
    vector <int> t[N];
    int f[N];
    
    int main()
    {
        scanf("%d%d",&m,&n);
        int st,ed;
        for(int i=1;i<=n;i++)
            scanf("%d%d",&st ,&ed ),ed +=st ,t[st ].push_back(ed);
        
        for(int i=m;i;i--)
        {
            int sz=t[i].size();
            if(!sz) 
            {
                f[i]=f[i+1]+1;
                continue;
            }
            for(int j=0;j<sz;j++)
            {
                ed=t[i][j];
                f[i]=max(f[i],f[ed ]);
            }
        }
        
        printf("%d
    ",f[1]);
        return 0;
    } 

    2>相似基因

    #include<cstdio>
    #include<cstdlib>
    #include<iostream> 
    #include<cstring> 
    using namespace std;
    int n1,n2;
    const int N=103;
    char s1[N],s2[N];
    int d1[N],d2[N];
    const int tab[5][5]=
    {
        {5,-1,-2,-1,-3},
        {-1,5,-3,-2,-4},
        {-2,-3,5,-2,-2},
        {-1,-2,-2,5,-1},
        {-3,-4,-2,-1,0}
    };
    int f[N][N];
    
    int main()
    {
        scanf("%d%s",&n1,s1+1);
        scanf("%d%s",&n2,s2+1);
        for(int i=1;i<=n1;i++)
        {
            if(s1[i]=='A') d1[i]=0;
            else if(s1[i]=='C') d1[i]=1;
            else if(s1[i]=='G') d1[i]=2;
            else if(s1[i]=='T') d1[i]=3;
        }
        for(int i=1;i<=n2;i++)
        {
            if(s2[i]=='A') d2[i]=0;
            else if(s2[i]=='C') d2[i]=1;
            else if(s2[i]=='G') d2[i]=2;
            else if(s2[i]=='T') d2[i]=3;
        }
            
        memset(f,-0x3f,sizeof(f));
        f[0][0]=0;for(int i=1;i<=n2;i++) f[0][i]=f[0][i-1]+tab[d2[i]][4];
        for(int i=1;i<=n1;i++) f[i][0]=f[i-1][0]+tab[d1[i]][4];
        
        for(int i=1;i<=n1;i++)
            for(int j=1;j<=n2;j++)
        {
            f[i][j]=max(f[i-1][j-1]+tab[d1[i]][d2[j]],
                max(f[i-1][j]+tab[d1[i]][4],  f[i][j-1]+tab[d2[j]][4]) );
            //printf("%d %d %d
    ",f[i-1][j-1]+tab[d1[i]][d2[j]],f[i-1][j]+tab[d1[i]][4],f[i][j-1]+tab[d2[j]][4]);
            //printf("%d
    ",f[i][j]);
        }
        
        printf("%d
    ",f[n1][n2]);
        return 0;
    }

     3>分离与合体

    就是把单点合并起来,求最值

    比较有特色的,就是最后的方案输出:

    LYD 请你编程求出最终可以获得的最大总价值,

    并按照分离阶段从前到后,区域从左到右的顺序,输出发生分离区域编号。若有多种方案,选择分离区域尽量靠左的方案(也可以理解为输出字典序最小的)。

    例如先打印一分为二的区域,然后从左到右打印二分为四的分离区域,然后是四分为八的……

    我用的是queue去bfs

    #include<cstdio>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    const int N=303;
    int n,d[N],f[N][N],pth[N][N];
    int max(int a,int b)
    { return a>b ?a :b; }
    
    struct node
    {
        int x,y;
        node(int xx,int yy)
        { x=xx,y=yy; }
        node(){}
    };
    void get_path(int l,int r)
    {
        queue <node> q;
        q.push(node(1,n));
        while(!q.empty() )
        {
            node nw=q.front(); q.pop();
            
            int cut=pth[nw.x ][nw.y ];
            printf("%d ",cut);
            if(cut>nw.x ) q.push(node(nw.x ,cut)) ;
            if(cut+1<nw.y ) q.push(node(cut+1,nw.y )) ;
        }
    }
    
    int main()
    {    
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&d[i]);
        
        for(int len=1;len<n;len++)
            for(int i=1,j=1+len;j<=n;i++,j++)
            {
                int t=d[i]+d[j];
                for(int k=i;k<j;k++)
                    if(t*d[k]+f[i][k]+f[k+1][j] >f[i][j])
                        f[i][j]=f[i][k]+f[k+1][j]+(d[i]+d[j])*d[k],
                        pth[i][j]=k;
            }
        
        printf("%d
    ",f[1][n]);
        get_path(1,n);
        return 0;
    }

     4>加分二叉树

    一道披着树形dp外皮的区间dp

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #define ll long long
    using namespace std;
    int n;
    const int N=33;
    int pth[N][N];
    ll d[N],f[N][N];
    ll max(ll a,ll b)
    { return a>b ?a :b; }
    
    void get_path(int l,int r)
    {
        if(pth[l][r])
        {
            printf("%d ",pth[l][r]);
            get_path(l,pth[l][r]-1);
            get_path(pth[l][r]+1,r);
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lld",&d[i]);
        
        for(int i=1;i<=n;i++)  f[i][i]=d[i],pth[i][i]=i;
        for(int len=1;len<n;len++)
            for(int i=1,j=1+len;j<=n;i++,j++)
            {
                int t1=f[i+1][j]+d[i],t2=f[i][j-1]+d[j];
                if(t1<t2)
                {
                    if(f[i][j]<t2)
                        f[i][j]=t2,pth[i][j]=j;
                }
                else
                    if(f[i][j]<t1)
                        f[i][j]=t1,pth[i][j]=i;
                
                for(int k=i+1;k<j;k++)
                {
                    int t=f[i][k-1]*f[k+1][j] +d[k];
                    if(t>f[i][j])
                        f[i][j]=t,pth[i][j]=k;
                }
            }
        
        printf("%lld
    ",f[1][n]);
        get_path(1,n);
        return 0;
    }
  • 相关阅读:
    pytorch torchversion标准化数据
    pytorch 中HWC转CHW
    pytorch torchversion自带的数据集
    pytorch Dataset数据集和Dataloader迭代数据集
    pytorch Model Linear实现线性回归CUDA版本
    pytorch实现手动线性回归
    pytorch中的前项计算和反向传播
    pytorch中CUDA类型的转换
    pytorch中tensor的属性 类型转换 形状变换 转置 最大值
    LightOJ 1074 spfa判断负环
  • 原文地址:https://www.cnblogs.com/xwww666666/p/11357205.html
Copyright © 2011-2022 走看看