1. 程式人生 > >[UVa-437] The Tower of Babylon

[UVa-437] The Tower of Babylon

情況 .net ros turn 無限 font == family sof

DAG建模基礎;

傳送門:$>here<$

題意

n種長方體,各有無限個。可以橫豎側擺放。只有一個長方形的底面,長小於且寬小於令一個底面才可以疊在上面。問最多疊多高?

數據範圍:$n \leq 30$

Solution

建模

將木塊的6種狀態(不是3種)作為不同物體考慮。若a能在b下面,那麽連一條a->b的邊,權值為b的高。至於第一塊的高,考慮使用虛擬點。

求最長

已經將所有可能情況歸結在圖中了。顯然這個圖一定無環。所以利用DAG的性質,$O(n^2)$求最長路即可。

DAG求最長路的本質是DP。設$dp[i]$表示從$i$出發的最長路,由於不會有環,所以用所有$i$連出去的點進行轉移即可。換句話說這些連出去的點和$i$毫無關系,是個獨立的子問題。之所以叫它DP,是因為DAG裏是可以有重復的子問題的(樹就沒有)

透過題解看本質

何時利用圖建模

二元關系可以利用圖來建模。在這道題中,一塊木塊能否放在另一塊上面是一個二元關系。而在建模過程中,每一個木塊的狀態是唯一的,像這種木塊翻轉的應當看做兩種情況。

my code

註意有6種,而不是3種。底面的長寬也是需要交換的!!!

當然在代碼實現的過程中為了方便依然可以只存三種情況,因為底面長寬交換不影響高,所以可以以兩種狀態存在,至於放上來的木塊,只要橫豎以一種狀態能夠放上就可以。因為一塊木塊一旦放完,對於剩余的木塊它就是底,因此橫豎都無所謂。

/*By DennyQi 2019*/
#include <cstdio>
#include 
<queue> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int MAXN = 10010; const int MAXM = 20010; const int INF = 0x3f3f3f3f; inline int Max(const int a, const int b){ return (a > b) ? a : b; } inline int Min(const int a, const int b){ return
(a < b) ? a : b; } inline int read(){ int x = 0; int w = 1; register char c = getchar(); for(; c ^ - && (c < 0 || c > 9); c = getchar()); if(c == -) w = -1, c = getchar(); for(; c >= 0 && c <= 9; c = getchar()) x = (x<<3) + (x<<1) + c - 0; return x * w; } struct Cuboid{ int x,y,z; }a[30001]; int n,N,Case,ans; int first[30001],nxt[30001],to[30001],cost[30001],cnt,dp[30001],pre[30001]; bool vis[30001]; inline bool Nest(int i, int j){ if((a[i].x>a[j].x && a[i].y>a[j].y) || (a[i].x>a[j].y && a[i].y>a[j].x)) return 1; return 0; } inline void add(int u, int v, int w){ cost[++cnt] = w, to[cnt] = v, nxt[cnt] = first[u], first[u] = cnt; } int Dfs(int u){ if(vis[u]) return dp[u]; vis[u] = 1; for(int i = first[u]; i; i = nxt[i]){ if(Dfs(to[i]) + cost[i] > dp[u]){ dp[u] = dp[to[i]] + cost[i]; pre[u] = to[i]; } } return dp[u]; } int main(){ while((N = read()) > 0){ n = N*3; memset(vis,0,sizeof(vis)); memset(dp,0,sizeof(dp)); memset(first,0,sizeof(first)); for(int i = 1; i <= N; ++i){ a[i].x = read(), a[i].y = read(), a[i].z = read(); a[i+N].x = a[i].x, a[i+N].y = a[i].z, a[i+N].z = a[i].y; a[i+N*2].x = a[i].y, a[i+N*2].y = a[i].z, a[i+N*2].z = a[i].x; } for(int i = 1; i <= n; ++i){ add(n+1,i,a[i].z); } for(int i = 1; i <= n; ++i){ for(int j = 1; j <= n; ++j){ if(i == j) continue; if(Nest(i,j)) add(i,j,a[j].z); } } ans = Dfs(n+1); ++Case; printf("Case %d: maximum height = %d\n",Case,ans); } return 0; }

[UVa-437] The Tower of Babylon