DAG 上的動態規劃

2021-08-20 02:55:42 字數 3578 閱讀 4440

暫存~dag 上的動態規劃(訓練指南—大白書)

2023年11月04日 16:42:48

閱讀數:1979

有向無環圖(dag,directed acyclic graph)上的動態規劃是學習動態規劃的基礎。很多問題都可以轉化為dag上的最長路、最短路或路徑計數問題。

一、矩形巢狀

題目描述:

有n個矩形,每個矩形可以用兩個整數a,b描述,表示它的長和寬。矩形x(a,b)可以巢狀在矩形y(c,d)中當且僅當ad(i) = max

其中e為邊集,最終答案為d(i).那如果要求輸出字典序最小的最長路徑呢?那麼必須找到第乙個最長的路徑的值然後遞迴輸出。

**:

[cpp]

view plain

copy

#include

#include

#include

#include

#include

using

namespace

std ;  

const

intmx = 1000 + 10 ;  

intn ;  

intg[mx][mx],dp[mx] ;  

struct

node  

t[mx] ;  

void

buildgraph() 

// 建圖

intdag(

intx) 

// 記憶化求解

return

ans ;  

}  void

print(

intx) 

// 列印路徑

}  intmain()  

intans=1 ;  

buildgraph() ;  

memset(dp,-1,sizeof

(dp)) ;  

for(

inti=0 ;i

for(int

i=0 ;i// 尋找第乙個點

if(dp[i]==ans)  

}  return

0 ;  

}  

二、硬幣問題

題目描述:

有n種硬幣,面值分別為v1,v2...,vn,每種都有無限多。給定非負整數s,可以選用多少個硬幣,使得面值之和恰好為s?輸出硬幣數目的最小值和最大值。0 <= n <= 100, 0 <= s <= 10000, 1 <= vi <= s。

解題思路:

本題的本質還是dag上的路徑問題。我們把每種面值看作乙個點,表示"還需要湊足的面值",則初始狀態為s,目標狀態為0。若當前的狀態i,每使用乙個硬幣j,狀態便轉移到i-vj。這個模型和巢狀矩形一題類似,但也有些明顯的不同之處:上題並沒有確定路徑的起點和終點(可以把任意矩形放在第乙個和最後乙個),而本題的起點必須是s,終點必須是0。把終點固定之後"最短路"才是有意義的。在巢狀矩形中,最短序列顯然是空(如果不允許空的話,就是單個矩形,不管怎樣都是平凡的),而本題的最短路徑卻不是那麼容易確定的。             

接下來考慮"硬幣問題"。注意到最長路和最短路的求法是類似的,下面只考慮最長路。由於終點固定,d(i)的確切含義變為"從節點i出發到節點0的最長路徑長度"。

**:[cpp]

view plain

copy

#include

#include

#include

#define inf 1<<30

#define maxn 100+10

using

namespace

std ;  

intv[maxn],n;  

intmin[maxn],max[maxn];  

inline

intmin(

inta,

intb)  

//列印可行的方案 

void

print_ans(

int* d,

ints)  

}  }  int

main()  

print_ans(min,s);    

printf("    min\n"

);  

print_ans(max,s);    

printf("    max\n"

);  

printf("min:%d max:%d\n"

,min[s],max[s]);     

}  return

0;  

}  

分析:本質上市乙個dag上的路徑問題,我們把每種面值看做乙個點,表示還需湊足的面值,則初始狀態為0,目標狀態為0,若當前在i,則每使用一枚硬幣j,狀態轉移到i-vj。

**:[cpp]

view plain

copy

#include

#define n 1100

intv[n],min[n],max[n],min_coins[n],max_coins[n];  

void

print_ans(

int*d,

ints, 

intn)   

printf("\n"

);  

}  int

main()   

for(i=1;i<=s;i++)  

if(max[i]

max[i]=max[i-v[j]]+1;  

max_coins[i]=j;  

}  //max[i]=max[i]>(max[i-v[j]]+1)?max[i]:(max[i-v[j]]+1);

}  }  

}  printf("%d %d\n"

,min[s],max[s]);  

print_ans(min_coins,s,n);  

print_ans(max_coins,s,n);  

}  return

0;  

}  

上面的**中,如果不需要輸出路徑的話,則可以不要max_coins和min_coins陣列,下面在寫乙個遞迴的。

[cpp]

view plain

copy

#include

#include

#define n 1100

intv[n],d[n],vis[n];  

intdp(

ints, 

intn)   

void

print_ans(

ints,

intn)  

}  }  

intmain()    

memset(vis,0,sizeof

(vis));  

vis[0]=1;  

d[0]=0;//終點狀態藥初始化為0,訪問過 

ans=dp(s,n);  

printf("%d\n"

,ans);  

print_ans(s,n);   

printf("\n"

);  

}  return

0;  

}  

只寫了求最長路徑的,如果要求最短路徑,則和最長路徑類似,在此省略。

DAG上的動態規劃

dag模型 有n個矩形,每個矩形用兩個整數a,b描述,表示長和寬,矩形 a,b 可以巢狀在矩形 c,d 中,當且僅當a小於c,b小於d或b小於c,a小於d。要解決的問題就是從眾多矩形中選出最多的矩形,使其可以按要求排成一列,若有多解,矩形編號的字典序要盡可能小。分析 按照書上的分析很簡單易懂,也容易...

DAG上的動態規劃

時間限制 3000 ms 記憶體限制 65535 kb 難度 4 描述 有n個矩形,每個矩形可以用a,b來描述,表示長和寬。矩形x a,b 可以巢狀在矩形y c,d 中當且僅當a 輸入 第一行是乙個正正數n 0輸出 每組測試資料都輸出乙個數,表示最多符合條件的矩形數目,每組輸出佔一行 樣例輸入 1 ...

DAG上的動態規劃

如需要課件ppt,聯絡我 dag 的定義 dag 意思是有向無環圖,所謂有向無環圖是指任意一條邊有方向,且不存在環路的圖。注 並非是一棵樹,邊數可以 經典例題 巢狀矩形 有n 個矩形,每個矩形可以用 ab來描述,表示長和寬。矩形 x ab 可以巢狀在矩形 y cd 中當且僅當 a或者b 相當於旋轉 ...