HDU 4001【DAG图的最长路径】

题意:

给出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>为有向边。

ContractedBlock.gif ExpandedBlockStart.gif View Code
  1 #include iostream
2 #include cstdio
3 #include vector
4 #include cstring
5 #include algorithm
6
7 using namespace std;
8
9 const int MAX = 1000 + 10;
10 struct TBlock
11 {
12 long long a, b, c, d;
13 }Block[MAX];
14
15 vectorint Link[MAX];
16 long long D[MAX];
17
18 long long getMax(long long a, long long b)
19 {
20 return a b b a;
21 }
22
23 long long getArea(int i)
24 {
25 return Block[i].a Block[i].b;
26 }
27
28 bool comp0(int b1, int b2)
29 {
30 return Block[b1].a = Block[b2].a && Block[b1].b = Block[b2].b;
31 }
32
33 bool comp1(int b1, int b2)
34 {
35 long long area1 = getArea(b1);
36 long long area2 = getArea(b2);
37 return Block[b1].a = Block[b2].a && Block[b1].b = Block[b2].b && area1 area2;
38 }
39
40 bool comp2(int b1, int b2)
41 {
42 return Block[b1].a Block[b2].a && Block[b1].b Block[b2].b;
43 }
44
45 void buildLink(int b1, int b2)
46 {
47 if(Block[b1].d == 0 && comp0(b1, b2))
48 Link[b1].push_back(b2);
49 else if(Block[b1].d == 1 && comp1(b1, b2))
50 Link[b1].push_back(b2);
51 else if(Block[b1].d == 2 && comp2(b1, b2))
52 Link[b1].push_back(b2);
53 }
54
55 long long dfs(int node)
56 {
57 if(D[node])
58 return D[node];
59 long long maxi = Block[node].c;
60 vectorintiterator ix = Link[node].begin();
61 while(ix != Link[node].end())
62 {
63 maxi = getMax(maxi, dfs(ix) + Block[node].c);
64 ++ix;
65 }
66 return D[node] = maxi;
67 }
68
69 int main()
70 {
71 freopen(in.txt, r, stdin);
72 int n;
73 while(scanf(%d, &n) == 1 && n)
74 {
75 for(int i = 1; i = n; ++i)
76 Link[i].clear();
77 int k = 1;
78 int flag = 1;
79 for(int i = 1; i = n; ++i)
80 {
81 scanf(%I64d%I64d%I64d%I64d, &Block[k].a, &Block[k].b, &Block[k].c, &Block[k].d);
82 if(Block[k].a Block[k].b)
83 {
84 long long temp = Block[k].a;
85 Block[k].a = Block[k].b;
86 Block[k].b = temp;
87 }
88 flag = 1;
89 for(int j = 1; j k; ++j)
90 {
91 if(Block[j].a == Block[k].a && Block[j].b == Block[k].b && Block[j].d == 0 && Block[k].d == 0)
92 {
93 Block[j].c += Block[k].c;
94 flag = 0;
95 break;
96 }
97 }
98 if(flag) for(int j = 1; j k; ++j)
99 {
100 buildLink(j, k);
101 buildLink(k, j);
102 }
103 k += flag;
104 }
105 k--;
106 long long ans = 0;
107 memset(D, 0, sizeof(D));
108 for(int i = 1; i = k; ++i)
109 {
110 ans = getMax(ans, dfs(i));
111 }
112 printf(%I64dn, ans);
113 }
114 return 0;
115 }

转载于:https://www.cnblogs.com/Kenfly/archive/2011/09/09/2172398.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值