[NOI1997] 积木游戏
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边”,如下图所示:
游戏规则如下:
- 从N块积木中选出若干块,并将它们分成M(l<=M<=N) 堆,称为第1堆,第2 堆…,第M堆。每堆至少有1块积木,并且第K堆中任意一块积木的编号要大于第K+1堆中任意一块积木的编号(2<=K<=M)。
- 对于每一堆积木,游戏者要将它们垂直摞成一根柱子,并要求满足下面两个条件:
- 除最顶上的一块积木外,任意一块积木的上表面同且仅同另一块积木的下表面接触,并且要求下面的积木的上表面能包含上面的积木的下表面,也就是说,要求下面的积木的上表面的两对边的长度分别大于等于上面的积木的两对边的长度。
- 对于任意两块上下表面相接触的积木,下面的积木的编号要小于上面的积木的编号。
最后,根据每人所摞成的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的最大高度
对于每一个积木有3种决策:
① 与前面积木合为一组 f[k][i][i][l]=max(f[k][i][j][t])+high[i]
② 自己另放一组 f[k][i][i][l]=max(f[k-1][i-1][j][t])+high[i]
③ 不放 f[k][i][j][l]=f[k][i-1][j][l]
其中0<=j<i 0<=t<=2 表示3种放置方式
ans=max(f[m][n][i][j]) 1<=i<=n,0<=j<=2
为了方便比较大小关系,我们可以先对输入每块积木的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]=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); }
2个错误:
1、j没有从0开始,从1开始,导致f[1][1][1][]的状态没有统计
2、转移中a,b,c交换错误,错误原因还没有找出
if(l==1) swap(b[i],c[i]);
else if(l==2) {swap(a[i],b[i]);swap(a[i],c[i]);}
if(a[i]<=a[j]&&b[i]<=b[j]) f[k][i][i][l]=max(f[k][i][i][l],f[k][i-1][j][0]+c[i]);
if(a[i]<=a[j]&&b[i]<=c[j]) f[k][i][i][l]=max(f[k][i][i][l],f[k][i-1][j][1]+c[i]);
if(a[i]<=b[j]&&b[i]<=c[j]) f[k][i][i][l]=max(f[k][i][i][l],f[k][i-1][j][2]+c[i]);
f[k][i][i][l]=max(f[k][i][i][l],f[k-1][i-1][j][0]+c[i]);
f[k][i][i][l]=max(f[k][i][i][l],f[k-1][i-1][j][1]+c[i]);
f[k][i][i][l]=max(f[k][i][i][l],f[k-1][i-1][j][2]+c[i]);
f[k][i][j][l]=f[k][i-1][j][l];
if(l==1) swap(b[i],c[i]);
else if(l==2) {swap(a[i],b[i]);swap(a[i],c[i]);}