vijos 1464 积木游戏 DP

Posted ( m Lweleth)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ([email protected])
  * @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\n", ans);
    return 0;
}

以上是关于vijos 1464 积木游戏 DP的主要内容,如果未能解决你的问题,请参考以下文章

vijos 1907 DP+滚动数组

[NOI1997] 积木游戏(dp)

Vijos 1565 多边形 区间DP

Vijos1240 朴素的网络游戏

dp积木城堡

Vijos1451圆环取数[环形DP|区间DP]