这是一道DP中的DAG,求最长路
【思路】
按照积木的长和宽从小到大排列
dp[i].c = max(dp[i].c , dp[j].c+b[i].c ) 为状态方程,其中1<=j<i
dp[j].c + b[i].c 表示当前积木i可以叠加在积木j上面时的值,若不能叠加则无需计算
注意排序中d的数值
注意数值溢出
【题意】
当d=0时,积木只能放在长和宽都小于等于它的积木上面
当d=1时,积木只能放在长和宽都小于等于它,并且面积小于它的积木上面
当d-2时,积木只能放在长和宽都小于它的积木上面
【AC代码】
#include <cstdio>
#include <string>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
struct block
{
int x,y,z,d;
}b[1005];
__int64 dp[1005];
int n;
bool cmp(block a, block b)
{
if(a.x != b.x) return a.x<b.x;
if(a.y != b.y) return a.y<b.y;
return a.d>b.d;
}
void DP()
{
__int64 ans = b[0].z;
for(int i=0; i<n; i++)
{
dp[i] = b[i].z;
ans = max(ans, dp[i]);
}
for(int i=1; i<n; i++)
{
if(b[i].d == 0)
{
for(int j=0; j<i; j++)
{
if(b[j].x<=b[i].x && b[j].y<=b[i].y)
dp[i] = max(dp[i], dp[j]+b[i].z);
}
}
else if(b[i].d == 1)
{
for(int j=0; j<i; j++)
{
if((b[j].x<=b[i].x && b[j].y<b[i].y)||(b[j].x<b[i].x && b[j].y<=b[i].y))
dp[i] = max(dp[i], dp[j]+b[i].z);
}
}
else if(b[i].d == 2)
{
for(int j=0; j<i; j++)
{
if(b[j].x<b[i].x && b[j].y<b[i].y)
dp[i] = max(dp[i], dp[j]+b[i].z);
}
}
ans = max(ans, dp[i]);
}
printf("%I64d\n",ans);
}
int main()
{
while(1)
{
scanf("%d",&n);
if (n==0) break;
for(int i=0; i<n; i++)
{
scanf("%d%d%d%d",&b[i].x, &b[i].y, &b[i].z, &b[i].d);
if(b[i].x<b[i].y)
swap(b[i].x, b[i].y);
}
sort(b, b+n, cmp);
DP();
}
return 0;
}