????? 有向無環圖(DAG,Directed Acyclic Graph)上的動態規劃是學習動態規劃的基礎。很多問題都可以轉化為DAG上的最長路、最短路或路徑計數問題。
?? ?? 有n個矩形,每個矩形可以用兩個整數a,b描述,表示它的長和寬。矩形X(a,b)可以嵌套在矩形Y(c,d)中當且僅當a<c,b<d,或者b<c,a<d(相當于把矩形X旋轉90°)。例如(1,5)可以嵌套在(6,2)內,但不能嵌套在(3,4)內。你的任務是選出盡可能多的矩形排成一行。使得除了最后一個之外,每個矩形都可以嵌套在下一個矩形內。
分析:
?????? 矩形之間的"可嵌套"關系是一個典型的二元關系,二元關系可以用圖來建模。如果矩形X可以嵌套在矩形Y里,我們就從X到Y連一條有向邊。這個有向圖是無環的,因為一個矩形無法直接或間接地嵌套在自己的內部。換句話說,它是一個DAG。這樣,我們的任務便是求DAG上的最長路徑。
方法一:
#include "stdio.h"
#include "string.h"
#define maxn 1000+10 typedef struct { //矩形的數據結構,長、寬 int length; int width;
}rectangle;int G[maxn][maxn]; //DAG圖的矩陣表示
int d[maxn],n; //d[i]頂點i的最長路徑
rectangle rec[maxn];//打印出圖的鄰接矩陣,目的是確保建圖正確無誤
void print_Graph()
{printf("|矩 形|");for(int i=0;i<n;i++) printf("%2d,%2d|",rec[i].length,rec[i].width);printf("\n");for(int i=0;i<n;i++){for(int k=0;k<=n;k++)printf("------");printf("\n");printf("|%2d,%2d|",rec[i].length,rec[i].width);for(int j=0;j<n;j++){printf(" %d |",G[i][j]);}printf("\n");}
}//構造圖
void createGraph()
{memset(G,0,sizeof(G));for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(rec[i].length>rec[j].length && rec[i].width>rec[j].width){ G[i][j]=1; //rec[i] 包含 rec[j]}}}// print_Graph();
}//記憶化搜索程序
int dp(int i)
{int& ans=d[i]; //為該表項聲明一個引用,簡化對它的讀寫操作。 if(ans>0) return ans;ans=1;for(int j=0;j<n;j++){if(G[i][j]){int tmp=dp(j);ans=ans>tmp+1?ans:tmp+1; }}return ans;
}int main()
{int N;scanf("%d",&N);while(N-->0){int ans=0;scanf("%d",&n); for(int i=0;i<n;i++){int tmp1,tmp2;scanf("%d%d",&tmp1,&tmp2);rec[i].length=tmp1>tmp2?tmp1:tmp2;rec[i].width=tmp1<tmp2?tmp1:tmp2; }createGraph();//初始化記憶數組 memset(d,0,sizeof(d)); for(int i=0;i<n;i++){int tmp=dp(i);ans=ans>tmp?ans:tmp; }printf("%d\n",ans);} return 0;
}
題目來源NYOJ:
http://acm.nyist.net/JudgeOnline/problem.php?pid=16
方法二:可以點我!