zoukankan      html  css  js  c++  java
  • 算法设计与分析——电路布线(动态规划)

    一、问题描述

    在一块电路板的上下两端分别有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;
        }
    }
  • 相关阅读:
    Linux配置SSH公钥认证与Jenkins远程登录进行自动发布
    在阳台上种花生
    已知传递函数,求幅频响应?
    win8快速锁屏
    word2016怎么让目录索引显示在左边?
    Matlab 瑞利信道仿真
    rayleighchan实现瑞利多径衰落信
    2017电商趋势
    【连载7】二手电商平台的账号与信用体系
    【连载6】二手电商APP的导购功能与关系链机制分析
  • 原文地址:https://www.cnblogs.com/wkfvawl/p/11660698.html
Copyright © 2011-2022 走看看