HDU4001-To Miss Our Children Time(DAG动态规划)

来源:互联网 发布:医学数据库检索方法 编辑:程序博客网 时间:2024/05/22 06:20

To Miss Our Children Time

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 3462    Accepted Submission(s): 898


Problem Description
Do you remember our children time? When we are children, we are interesting in almost everything around ourselves. A little thing or a simple game will brings us lots of happy time! LLL is a nostalgic boy, now he grows up. In the dead of night, he often misses something, including a simple game which brings him much happy when he was child. Here are the game rules: There lies many blocks on the ground, little LLL wants build "Skyscraper" using these blocks. There are three kinds of blocks signed by an integer d. We describe each block's shape is Cuboid using four integers ai, bi, ci, di. ai, bi are two edges of the block one of them is length the other is width. ci is
thickness of the block. We know that the ci must be vertical with earth ground. di describe the kind of the block. When di = 0 the block's length and width must be more or equal to the block's length and width which lies under the block. When di = 1 the block's length and width must be more or equal to the block's length which lies under the block and width and the block's area must be more than the block's area which lies under the block. When di = 2 the block length and width must be more than the block's length and width which lies under the block. Here are some blocks. Can you know what's the highest "Skyscraper" can be build using these blocks?
 

Input
The input has many test cases.
For each test case the first line is a integer n ( 0< n <= 1000) , the number of blocks.
From the second to the n+1'th lines , each line describing the i‐1'th block's a,b,c,d (1 =< ai,bi,ci <= 10^8 , d = 0 or 1 or 2).
The input end with n = 0.
 

Output
Output a line contains a integer describing the highest "Skyscraper"'s height using the n blocks.
 

Sample Input
310 10 12 010 10 12 110 10 11 2210 10 11 110 10 11 10
 

Sample Output
2411
 
题意:有3种若干个长方体木块(种类号为0、1、2),他们可以摞在别的木块之上的规则各不相同,规则如下:
 
给出n个长方体,其长宽高分别为ai,bi,ci,di, di为长方体的类型。di为0的长方体,当其长宽分别大于或等于某个长方体时,可以摆放在某个长方体上面。di为1的长方体,当其长宽分别大于或等于且其底面积大于某个长方体时,可以摆放在某个长方体上面。di为2的长方体,当其长宽分别大于某个长方体时,可以摆放在某个长方体上面。
 
问,这些方块最多可以摞多高?
 
分析:

这题是经典的求DAG图上的最长路径题目。用边表示一个长方体可摆放在另一个长方体这种关系,给所有可能组合的两个长方体造边,则会得到DAG图,这题有个特别小心的地方是当长方体的类型di为0时,有可能出现环的情况,最方便的处理方法是缩点,也就是把ai=ai,bi=bi,di=0的长方体合并成一个,ci为所有合并的长方体的ci之和,这样环就消失了。

可以用记忆搜索来快速解决DAG图,用D[i]表示以第i个长方体为顶时的最大高度,转移方程是:D[i]=max{D[j],D[k]...} + ci, 其中<i,j>,<i,k>为有向边。

代码如下:
#include<stdio.h>#include<string.h>#define N 1010int map[N][N],n;long long d[N];struct node {    long long a,b,c,d;}set[N];void buildmap(int x, int y){    if(set[x].d==0&&set[x].a>=set[y].a&&set[x].b>=set[y].b)        map[x][y]=1;    else if(set[x].d==1&&set[x].a>=set[y].a&&set[x].b>=set[y].b&&set[x].a*set[x].b>set[y].a*set[y].b)        map[x][y]=1;    else if(set[x].d==2&&set[x].a>set[y].a&&set[x].b>set[y].b)        map[x][y]=1;}long long dp(int i) {int j;if(d[i]>0)return d[i];d[i]=set[i].c;for(j=0;j<n;j++)if(map[i][j] && d[i]<dp(j)+set[i].c)d[i]=dp(j)+set[i].c;return d[i];}int main() {    int i,flag,j,k;    long long temp,ans;    while(scanf("%d",&n),n) {memset(map,0,sizeof(map));        for(i=0,k=0;i<n;i++){            scanf("%I64d %I64d %I64d %I64d",&set[k].a,&set[k].b,&set[k].c,&set[k].d);//scanf("%d %d %d %d",&set[k].a,&set[k].b,&set[k].c,&set[k].d);            if(set[k].a<set[k].b){                temp=set[k].a;                set[k].a=set[k].b;                set[k].b=temp;            }            for(j=0,flag=1;j<k;j++){//对于第一种方块,自身自之间可能出现环,要缩点                 if(set[j].a==set[k].a&&set[j].b==set[k].b&&set[j].d==0&&set[k].d==0){                    set[j].c+=set[k].c;//将两种大小相同的方体高度加到一块                     flag=0;                 }            }            if(flag==1){                for(j=0;j<k;j++){                    buildmap(j,k);//j到k是否建立连线                     buildmap(k,j);                }             }            k+=flag;        }        memset(d,0,sizeof(d));        for(i=0,ans=0;i<k;i++){            if(ans<dp(i))                ans=dp(i);        }        printf("%I64d\n",ans);       }    return 0;}