電路佈線問題
製作電路板時,將n條連線分佈到若干絕緣層上。在同一層的連線不相交。電路佈線問題就是要確定將哪些連線安排到第一層上,使該層上有儘可能多的連線。
輸入一個整數n代表接線柱的數量,輸入n個數代表與上接線柱連接的下接線柱編號
樣例輸入
10
4
解:
例如,給定如圖的電路板。從10條連線中,選取不相交的最大連線集合。用a(i)=j表示要求上排的第i個接線柱要求接到下排的第 j 個接線柱。
在圖中,a(1)=8 , a(2)=7, a(1)=4, a(1)=2, a(1)=5, a(1)=1, a(1)=9, a(1)=3, a(1)=10, a(1)=6。
如果使得(i , a[i])與(j , a[j])不相交,假設 j>I 則兩條線不相交的充分必要條件爲 a[j]>a[i]。在製作電路板時,要求將這n條連線分佈到若干絕緣層上。在同一層上的連線不相交。電路佈線問題要確定將哪些連線安排在第一層上,使得該層上有儘可能多的連線。換句話說,該問題要求確定所有導線集的最大不相交子集。
記N(i,j){(t,a(t)) | t<=i,a(t)<=j }代表上接線柱小於等於i並且下接線柱小於等於j的連線的集合。N(i,j)的最大不相交子集爲MNS(i,j),假設MNS(i,j)中的連線數目爲dp[i][j];
下面對MNS(i,j)進行判斷區分:
(1) 當i = 1時
①如果j>=a[i],爲了考慮更多的連線,則(i,a[i])應當在集合MNS(i,j) 中,即dp(i,j)=1;
②如果j<a[i],此時則(i,a[i])不應放在集合MNS(i,j) 中,即dp(i,j)=0
(2)當i >1時
①j<a(i)。
此時,(i,a(i))不屬於MNS(i,j)。故在這時,MNS(i,j) =MNS(i-1,j),從而dp(i,j)=dp(i-1,j)。
②j >=a(i)。
若(i, a(i))∈MNS(i,j),則對任意(t, a(t))∈MNS(i,j)有t <i且a(t)<a(i);否則,(t,a(t))與(i,a(i))相交。在這種情況下MNS(i,j)-{(i,a(i))}是N(i-1,a(i)-1)的最大不相交子集。否則,子集MNS(i-1,a(i)-1)∪{(i,a(i))}包含於N(i,j)是比MNS(i,j)更大的N(i,j)的不相交子集。這與MNS(i,j)的定義相矛盾。
若(i, a(i))不屬於MNS(i,j),則對任意(t, a(t))∈MNS(i,j),有t<i。從而MNS(i,j)包含於N(i-1,j),因此,dp(i,j)≤dp(i-1,j)。另一方面,MNS(i-1,j)包含於N(i,j),故又有dp(i,j)≥dp(i-1,j),從而Size(i,j)=Size(i-1,j)。
(i,a[i])屬於MNS(i,j),則dp(i,j)=dp(i-1,a[i])+1;
(i,a[i])不屬於MNS(i,j),則dp(i,j)=dp(i-1,j);
所以遞推公式:
1)當i=1時
(2)當i>1時
#include <stdio.h>
#include <string.h>
#define MAX(a, b) ((a)>(b)?(a):(b))
int main()
{
int n;
int a[100],dp[100][100];
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
memset(dp,0,sizeof(dp));
for(int j=1;j<=n;j++)
{
if(j<a[1])
dp[1][j]=0;
else
dp[1][j]=1;
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(j<a[i])
dp[i][j]=dp[i-1][j];
else
dp[i][j]=MAX(dp[i-1][j],dp[i-1][a[i]-1]+1);
}
}
printf("%d\n",dp[n][n]);
return 0;
}