算法設計與分析——電路布線(動態規划)


一、問題描述

在一塊電路板的上下兩端分別有n個接線柱。根據電路設計,要求用導線 (i,π(i)),將上端接線柱 i 與下端接線柱 π(i) 相連,
如圖,其中 π(i),1<=i<=n,是(1,2……,n)的一個排列。導線(i,π(i))稱為該電路板上的第i條連線。對於任何 1<=i<s<=n,第i條連線和第s條連線相交的充分且必要條件是 π(i) > π(s)。

在制作電路板時,要求將這n條線分布到若干個絕緣層上,在同一層上的連線不能相交。電路布線問題要確定將哪些連線安排在第一層上,使得該層上有盡可能多的連線。換句話說,該問題要求確定導線集Nets = { (i,π(i)),1<=i<=n }的最大不相交子集。

 二、算法思路

1、最優子結構性質

N(i,j)表示上面節點i與下面節點j連線的左側區域內(包括i j連線)的連線集合,MNS(i,j)表示連線左側區域內最大不相交連線子集,Size(i,j)表示MNS(i,j)集合中連線的個數。

在這里注意N(i,j)和MNS(i,j)表示的都是集合!!內存儲的是連線,Size(i,j)存儲的才是最大不相交連線的個數!!

2、遞歸計算最優值

當i=1的時候很好理解。

當i>1時,我們還是看上面的那個連線圖。

當j<π(i)時,t[8][9]=t[7][9]。

當j>=π(i)時,t[7][9]=[6][8]+1。琢磨一下是不是符合表達式?

void MNS(int C[],int n,int **size)  
{  
    for(int j=0;j<C[1];j++)  
    {  
        size[1][j]=0;  
    }  
  
    for(int j=C[1]; j<=n; j++)  
    {  
        size[1][j]=1;  
    }  
  
    for(int i=2; i<n; i++)  
    {  
        for(int j=0; j<C[i]; j++)  
        {  
            size[i][j]=size[i-1][j];//當i<c[i]的情形  
        }  
        for(int j=C[i]; j<=n; j++)  
        {  
            //當j>=c[i]時,考慮(i,c[i])是否屬於MNS(i,j)的兩種情況  
            size[i][j]=max(size[i-1][j],size[i-1][C[i]-1]+1);  
        }  
    }  
    size[n][n]=max(size[n-1][n],size[n-1][C[n]-1]+1);  
}  

3、構造最優解

 

 紅色標明的就是算法選擇的路徑(向上優先,也可以用向左優先,答案都是四個,但值會有一點不同)。在斜角值改變時可以取得所求的子集。即 9->10,7->9, 5->5, 3->4

void Traceback(int C[],int **size,int n,int Net[],int& m)  
{  
    int j=n;  
    m=0;  
    for(int i=n;i>1;i--)  
    {  
        if(size[i][j]!=size[i-1][j])//此時,(i,c[i])是最大不相交子集的一條邊  
        {  
            Net[m++]=i;  
            j=C[i]-1;//更新擴展連線柱區間  
        }  
    }  
    if(j>=C[1])//處理i=1的情形  
    {  
        Net[m++]=1;  
    }  
}  

4、計算復雜性

5、演示代碼

#include <iostream>
using namespace std;

const int N = 10;

void MNS(int C[],int n,int **size);
void Traceback(int C[],int **size,int n,int Net[],int& m);

int main()
{
    int c[] = {0,8,7,4,2,5,1,9,3,10,6};//下標從1開始
    int **size = new int *[N+1];

    for(int i=0; i<=N; i++)
    {
        size[i] = new int[N+1];
    }

    MNS(c,N,size);

    cout<<"電路布線最大不相交連線數目為:"<<size[N][N]<<endl;

    int Net[N],m;
    Traceback(c,size,N,Net,m);

    cout<<"最大不相交連線分別為:"<<endl;
    for(int i=m-1; i>=0; i--)
    {
        cout<<"("<<Net[i]<<","<<c[Net[i]]<<") ";
    }
    cout<<endl;
    return 0;
}

void MNS(int C[],int n,int **size)
{
    for(int j=0;j<C[1];j++)
    {
        size[1][j]=0;
    }

    for(int j=C[1]; j<=n; j++)
    {
        size[1][j]=1;
    }

    for(int i=2; i<n; i++)
    {
        for(int j=0; j<C[i]; j++)
        {
            size[i][j]=size[i-1][j];//當i<c[i]的情形
        }
        for(int j=C[i]; j<=n; j++)
        {
            //當j>=c[i]時,考慮(i,c[i])是否屬於MNS(i,j)的兩種情況
            size[i][j]=max(size[i-1][j],size[i-1][C[i]-1]+1);
        }
    }
    size[n][n]=max(size[n-1][n],size[n-1][C[n]-1]+1);
}

void Traceback(int C[],int **size,int n,int Net[],int& m)
{
    int j=n;
    m=0;
    for(int i=n;i>1;i--)
    {
        if(size[i][j]!=size[i-1][j])//此時,(i,c[i])是最大不相交子集的一條邊
        {
            Net[m++]=i;
            j=C[i]-1;//更新擴展連線柱區間
        }
    }
    if(j>=C[1])//處理i=1的情形
    {
        Net[m++]=1;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM