1. 程式人生 > >[NOI1997] 積木遊戲(dp)

[NOI1997] 積木遊戲(dp)

ble n) scrip open iframe image upload targe name

COGS 261. [NOI1997] 積木遊戲

http://www.cogs.pro/cogs/problem/problem.php?pid=261

★★ 輸入文件:buildinggame.in 輸出文件:buildinggame.out 簡單對比
時間限制:1 s 內存限制:128 MB

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個積木的尺寸,每行有三個1至1000之間的整數,分別表示該積木a 邊,b邊和c邊的長度。同一行相鄰兩個數之間用一個空格符隔開。

輸出文件只有一行,為一個整數,表示M根柱子的高度之和。

樣例

輸入文件

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

輸出文件

24


/*
f[k][i][j][l] 表示 前i個積木分為k組,第k組最後一個是j,j的擺放方式為l的最大高度
為了方便比較大小關系,可以先對輸入每塊積木的a,b,c排序,這樣在DP中就不用判斷同一塊積木的長寬高
排序方式,每塊積木最小的參數為a,中間的是b,最大的為c
狀態表示方法:
0 表示  ab面為底;1 表示 ac面為底; 2表示bc面為底
*/
#include<cstdio>
#include<algorithm>

using namespace std;
int n,m,a[101],b[101],c[101],f[101][101][101][3];

int main()
{
    freopen("buildinggame.in","r",stdin);
    freopen("buildinggame.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
        if(a[i]>b[i]) swap(a[i],b[i]);
        if(b[i]>c[i]) swap(b[i],c[i]);
        if(a[i]>b[i]) swap(a[i],b[i]);
    }
    
    for(int k=1;k<=m;k++)
     for(int i=1;i<=n;i++)
      for(int j=0;j<i;j++)
       for(int l=0;l<=2;l++)
       {
            int aa,bb,cc;
            if(l==0) aa=a[i],bb=b[i],cc=c[i];
            else if(l==1) aa=a[i],bb=c[i],cc=b[i];
            else aa=b[i],bb=c[i],cc=a[i];    
            if(aa<=a[j]&&bb<=b[j])  f[k][i][i][l]=max(f[k][i][i][l],f[k][i-1][j][0]+cc);
            if(aa<=a[j]&&bb<=c[j])  f[k][i][i][l]=max(f[k][i][i][l],f[k][i-1][j][1]+cc);
            if(aa<=b[j]&&bb<=c[j])  f[k][i][i][l]=max(f[k][i][i][l],f[k][i-1][j][2]+cc);
            f[k][i][i][l]=max(f[k][i][i][l],f[k-1][i-1][j][0]+cc);
            f[k][i][i][l]=max(f[k][i][i][l],f[k-1][i-1][j][1]+cc);
            f[k][i][i][l]=max(f[k][i][i][l],f[k-1][i-1][j][2]+cc);
            f[k][i][j][l]=max(f[k][i][j][l],f[k][i-1][j][l]);
       }
    int ans=0;
    for(int i=1;i<=n;i++)
     for(int j=0;j<=2;j++)
       ans=max(ans,f[m][n][i][j]);
    printf("%d",ans);
}

[NOI1997] 積木遊戲(dp)