• Vijos1392拼拼图的小衫[背包DP|二维信息DP]


    背景

    小杉的幻想来到了经典日剧《死亡拼图》的场景里……
    被歹徒威胁,他正在寻找拼图(-.-干嘛幻想这么郁闷的场景……)。

    突然广播又响了起来,歹徒竟然又有了新的指示。

    小杉身为新一代的汤浅,有责任带领大家脱离危险!

    (若对情节有任何疑问,请观看原剧)

    描述

    歹徒告诉小杉,他正在寻找的拼图块其实可以拼成N个 有顺序的 完整的拼图。

    每个完整的拼图由若干个拼图块组成。

    歹徒要求小杉把拼图按拼出的顺序划分成M个集合,一个拼图集合由若干个完整的拼图组成,并且总的拼图块的数目不超过T。并且,构成集合的拼图是不能交叉的,例如,当拼图1与拼图3被放在拼图集合1中之后,拼图2就只能放进拼图集合1或者不放进任何拼图集合。

    小杉要找出划分成M个集合后,M个集合中最多能有多少个完整的拼图。

    格式

    输入格式

    每组测试数据的
    第一行有三个,为N,M,T(1<=N,M,T<=1000)
    第二行有N个数,按照拼出拼图的顺序给出N个拼图分别含有多少个拼图块(拼图块的个数是不超过T的正整数,并且你不必考虑在现实中是否真正存在该个数的拼图)。

    特别地,对于30%的数据,有1<=N,M<=100

    输出格式

    对每组数据输出一行一个数字,为M个拼图集合最多包含的拼图个数

    样例1

    样例输入1

    6 2 4
    1 1 3 1 2 2

    样例输出1

    5

    限制

    每个测试点1s

    提示

    对于样例数据,1个可行的方案如下
    拼图集合1放拼图1和拼图2,
    拼图集合2放拼图5和拼图6
    于是最多可以放4个拼图

    并且显然不存在能够放4个以上拼图的方案

    来源

    lolanv

    -----------------------

    题意:长度n的序列分成m段,每段选若干元素,使得总段数w不超过t,且选的最多

    -----------------------

    一开始想f[i][j][k]表示i个分j段,最后一段的w为k的最多拼图个数

    然后像背包一样转移,不选i或者选i,选的话可能是从本段来的,也可能是刚好新开一段

    把i滚动数组掉,维护一个mx[i][j]表示i个分j段段最大值,方便新开一段这个转移

    注意f[i][j][0]=mx[i-1][j-1]

    然后竟然做出来了,虽然很慢

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=1005;
    int n,m,t,w[N];
    int f[N][N],mx[N][N];
    void dp(){
        for(int i=1;i<=n;i++)
            for(int j=m;j>=1;j--){f[j][0]=mx[i-1][j-1];
                for(int k=t;k>0;k--){
                    int &now=f[j][k];
                    if(k-w[i]>=0) now=max(now,f[j][k-w[i]]+1);
                    mx[i][j]=max(mx[i][j],now);
                    //printf("%d %d %d %d
    ",i,j,k,now);
                }
            }
    }
    int main(int argc, const char * argv[]) {
        scanf("%d%d%d",&n,&m,&t);
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        dp();
        cout<<mx[n][m];
        return 0;
    }

    另一种很神的思路是,把后两个状态和状态值对换

    f[i][j]=c(a,b)表示前i个选j个的段数为a且额外要b个段数

    有点类似可行性,注意初始化

    速度好快

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=1005,INF=1e5;
    int n,m,t,w[N],ans=0;
    struct data{
        int a,b;
        data(int x=INF,int y=INF):a(x),b(y){}
    };
    data min(data x,data y){
        if(x.a<y.a) return x;
        if(x.a>y.a) return y;
        if(x.a==y.a) return x.b<y.b?x:y;
        return x;
    }
    data f[N][N];
    void dp(){
        for(int i=0;i<=n;i++) f[i][0]=data(0,0);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++){
                data tmp;
                if(w[i]+f[i-1][j-1].b<=t){tmp.a=f[i-1][j-1].a;tmp.b=f[i-1][j-1].b+w[i];}
                else{tmp.a=f[i-1][j-1].a+1;tmp.b=w[i];}
                f[i][j]=min(f[i-1][j],tmp);
                if(f[i][j].a<m) ans=max(ans,j);
                //printf("%d %d %d %d
    ",i,j,f[i][j].a,f[i][j].b);
            }
    }
    int main(int argc, const char * argv[]) {
        scanf("%d%d%d",&n,&m,&t);
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        dp();
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    XNA之3D文字
    SQL2005调用C#编写的DLL
    C#绘图工具之Rotate
    ASP.NET中的WebService
    数据库同步之复制技术
    C#之TCP消息的发送和接受
    Tsql清空表数据的两种方式truncate and delete
    Code First Migrations数据迁移方法
    MSSQLSERVER跨服务器连接
    windows下wget命令行下载工具的使用
  • 原文地址:https://www.cnblogs.com/candy99/p/5820269.html
Copyright © 2020-2023  润新知