zoukankan      html  css  js  c++  java
  • vijos 1464 积木游戏 DP

    描述

    积木游戏

    SERCOI 最近设计了一种积木游戏。每个游戏者有N块编号依次为1 ,2,…,N的长方
    体积木。对于每块积木,它的三条不同的边分别称为"a边"、"b边"和"c边"

    游戏规则如下:
    1、从N块积木中选出若干块,并将它们分成M(l<=M<=N) 堆,称为第1堆,第2 堆…,第M堆。每堆至少有1块积木,并且第K堆中任意一块积木的编号要大于第K+1堆中任意一块积木的编号(2<=K<=M)。

    2.对于每一堆积木,游戏者要将它们垂直摞成一根柱子,并要求满足下面两个条件:
    (1)除最顶上的一块积木外,任意一块积木的上表面同且仅同另一块积木的下表面接触,并且要求下面的积木的上表面能包含上面的积木的下表面,也就是说,要求下面的积木的上表面的两对边的长度分别大于等于上面的积木的两对边的长度。

    (2)对于任意两块上下表面相接触的积木,下面的积木的编号要小于上面的积木的编号。

    最后,根据每人所摞成的M根柱子的高度之和来决出胜负。

    请你编一程序,寻找一种摞积木的方案,使得你所摞成的M根柱子的高度之和最大。

    格式

    输入格式

    第一行有两个正整数N和M(1<=M<=N<=100),分别表
    示积木总数和要求摞成的柱子数。这两个数之间用一个空格符隔开。接下来N行依次是编号
    从1到N的N个积木的尺寸,每行有三个;至1000之间的整数,分别表示该积木a边,b边
    和c边的长度。同一行相邻两个数之间用一个空格符隔开。

    输出格式

    只有一行,为一个整数,表示M根柱子的高度之和。

    样例1

    样例输入1[复制]

    4 2
    10 5 5
    8 7 7
    2 2 2
    6 6 6

    样例输出1[复制]

    24

    限制

    各个测试点1s

    题意:中文题。

    思路:可以看出就是个背包,主要是如何考虑状态,高度和底面大小的关系,其实我们可以将某块积木的某边的高作为状态,因为积木是按照顺序选取的,所以dp[i][j][k]代表第i柱时,选取第j块积木,并以它的第k条边作为高。这样我们每一柱都当做LIS来做,同时将上一个值转移过来,所以可以用滚动数组优化空间。

    /** @Date    : 2016-12-03-22.23
      * @Author  : Lweleth (SoungEarlf@gmail.com)
      * @Link    : https://github.com/
      * @Version :
      */
    
    #include<bits/stdc++.h>
    #define LL long long
    #define PII pair<int ,int>
    #define MP(x, y) make_pair((x),(y))
    #define fi first
    #define se second
    #define PB(x) push_back((x))
    #define MMG(x) memset((x), -1,sizeof(x))
    #define MMF(x) memset((x),0,sizeof(x))
    #define MMI(x) memset((x), INF, sizeof(x))
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    const int N = 1e5+20;
    const double eps = 1e-8;
    
    
    int dp[110][110][3];//第i根 第j个 第k边为高 的最大值
    int a[110][3];
    int main()
    {
        int n, m;
        cin >> n >> m;
        for(int i = 1; i <= n; i++)
            for(int j = 0; j < 3; j++)
                scanf("%d", &a[i][j]);
    
        MMF(dp);
        int ma1, ma2, mi1, mi2;
        int ans = 0;
        int sum = 0;
        for(int i = 1; i <= m; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                for(int k = 0; k < j; k++)//从0开始
                {
                    for(int l = 0; l < 3; l++)
                    {
    					int l1 = (l + 2) % 3;
         				int r1 = (l + 1) % 3;
                        for(int o = 0; o < 3; o++)
                        {  
                            int l2 = (o + 2) % 3;
                            int r2 = (o + 1) % 3;
                            ma1 = a[j][l1];
                            mi1 = a[j][r1];
                            ma2 = a[k][l2];
                            mi2 = a[k][r2];
                            if(ma1 < mi1)
                                swap(ma1, mi1);
                            if(ma2 < mi2)
                                swap(ma2, mi2);
                            //cout << ma1 << mi1 << " " << ma2 << mi2 << endl;
                            if(ma2 >= ma1 && mi2 >= mi1)
                                dp[i][j][l] = max(dp[i][j][l], dp[i][k][o] + a[j][l]);
                            dp[i][j][l] = max(dp[i][j][l], dp[i-1][k][o] + a[j][l]);
                            ans = max(ans, dp[i][j][l]);
                        }
                    }
                }
            }
        }
        printf("%d
    ", ans);
        return 0;
    }
    
    
  • 相关阅读:
    1.造一个句子先造出 主谓宾 或主系表,或therebe 这个句子就确定了
    电脑族应每天赤脚走15分钟
    10我操介词
    2.在英语句子中,什么时候用助动词do\does ,什么时候用be动词am\is\are?
    6.英语单词末尾的——s,什么时候发S,什么时候发Z
    转 Dll创建一个"日历"窗体(一)
    2012 MultiUniversity Training Contest 2
    最大流 基础
    HDOJ 4006 The kth great number(优先队列)
    树状数组
  • 原文地址:https://www.cnblogs.com/Yumesenya/p/6151895.html
Copyright © 2011-2022 走看看