zoukankan      html  css  js  c++  java
  • 凸多边形最优三角剖分的问题”

    有关“凸多边形最优三角剖分的问题”,这是《计算机算法设计与分析》(王晓东编著 第三版)第三章“动态规划”中的一道例题,代码如下:

    C/C++ code
     
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    “Point.h”
    class Point{
    public:
        int x;
        int y;
    };
     
    "MWTri.cpp"
    #include<iostream>
    #include"math.h"
    #include"Point.h"
    using namespace std;
     
    #define MAX 100
     
    int t[MAX][MAX];
    int s[MAX][MAX];
     
    int w(Point pt1,Point pt2,Point pt3){
     
        int d1=(int)sqrt((pt2.y-pt1.y)*(pt2.y-pt1.y)+(pt2.x-pt1.x)*(pt2.x-pt1.x));
        int d2=(int)sqrt((pt3.y-pt1.y)*(pt3.y-pt1.y)+(pt3.x-pt1.x)*(pt3.x-pt1.x));
        int d3=(int)sqrt((pt3.y-pt2.y)*(pt3.y-pt2.y)+(pt3.x-pt2.x)*(pt3.x-pt2.x));
        return d1+d2+d3;
    }
     
    void MinWeightTriangulation(Point * point,int n,int t[][MAX],int s[][MAX]){
     
        for(int i=1;i<=n;i++) t[i][i]=0;
        for(int r=2;r<=n;r++)
            for(int i=1;i<=n-r+1;i++){
                int j=i+r-1;
                t[i][j]=t[i+1][j]+w(point[i-1],point[i],point[j]);
                s[i][j]=i;
                for(int k=i+1;k<j;k++){
                    int u=t[i][k]+t[k+1][j]+w(point[i-1],point[k],point[j]);
                    if(u<t[i][j]){
                     
                        t[i][j]=u;
                        s[i][j]=k;
                    }
                }
            }
     
    }
     
    void main(){
     
        Point pt[5];
        pt[0].x=4;
        pt[0].y=1;
        pt[1].x=3;
        pt[1].y=2;
        pt[2].x=2;
        pt[2].y=2;
        pt[3].x=1;
        pt[3].y=1;
        pt[4].x=1;
        pt[4].y=0;
        //pt[5].x=4;
        //pt[5].y=1;
         
        /*for(int m=1;m<=4;m++)
            for(int n=1;n<=4;n++)
                s[m][n]=0;*/
     
        MinWeightTriangulation(pt,4,t,s);
        for(int m=1;m<=4;m++)
            for(int n=1;n<=4;n++)
                cout<<m<<" "<<n<<" "<<s[m][n]<<endl;
             
     
     
     
    }


    程序运行结果如下:

    C/C++ code
     
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    1 1 0
    1 2 1
    1 3 1
    1 4 1
    2 1 0
    2 2 0
    2 3 2
    2 4 2
    3 1 0
    3 2 0
    3 3 0
    3 4 3
    4 1 0
    4 2 0
    4 3 0
    4 4 0
    Press any key to continue
     
     
    #include    "windows.h"
    #include    <iostream>
    using    namespace    std;
     
    /*
      问题描述:
            把多边形0,...,n-1剖分成n-2个三角形,求给定的权值最小
            本程序定义权为:剖分弦的长度和
      程序功能:
            用两种方法求解上述问题(针对任意权的和针对本问题的)
            解法本质都是动态规划
         PS   :   
            动态规划很难,本程序难免会有错误,但是基本思路是正确的
            注释得很详细了
    */
     
    const    V    =    5;//5个顶点
     
    void    LoadData(float dist[][V]);
    /*
      解法1:
            重新定义权为:剖分弦的长度和加上多边形的周长(显然等价),重新求解
            本函数还适用于任何定义在剖分后的三角形上的权的情况(修改一下)
            例如权为三角形的面积的面积平方和
    */
    void    minWeightTriangulation1(int n, float dist[][V], float t[][V], int s[][V]);
    void    ShowSolution1(int s[][V], int i, int j);
     
    /*
      解法2:
            针对此问题的求解方法,不具有普遍适用性
    */
    void    minWeightTriangulation2(int n, float dist[][V], float t[][V+1], int s[][V+1]);
    void    ShowSolution2(int s[][V+1], int i, int j);
     
    void    end();
     
    int    main()
    {
        float    dist[V][V];
     
        float    t1[V][V];
        int    s1[V][V];
     
        float    t2[V+1][V+1];
        int    s2[V+1][V+1];
     
        LoadData(dist);
         
        minWeightTriangulation1(V, dist, t1, s1);
        cout<<"最优剖分权:"<<t1[1][4] - 2 - 1.414 * 3<<" 剖分弦: ";//要减去周长
        ShowSolution1(s1, 1, 4);
        cout<<endl;
     
        minWeightTriangulation2(V, dist, t2, s2);
        cout<<"最优剖分权:"<<t2[0][5]<<" 剖分弦: ";
        ShowSolution2(s2, 0, 5);
        cout<<endl;
     
         
        return    0;
    }
     
    void    LoadData(float    dist[][V])
    {
        dist[0][1] = dist[1][0] = 1;
        dist[1][2] = dist[2][1] = 1;
        dist[2][3] = dist[3][2] = 1.414;
        dist[3][4] = dist[4][3] = 1.414;
        dist[4][0] = dist[0][4] = 1.414;
        dist[0][2] = dist[2][0] = 1.414;
        dist[0][3] = dist[3][0] = 2;
        dist[1][3] = dist[3][1] = 2.236;
        dist[1][4] = dist[4][1] = 2.828;
        dist[2][4] = dist[4][2] = 2;
    }
     
    float    Weight(float dist[][V], int i, int j, int k)
    {
        return dist[i][j] + dist[j][k] + dist [k][i];
    }
     
    void    minWeightTriangulation1(int n, float dist[][V], float t[][V], int s[][V])
    {
    /*
        t[i][j]表示顶点为i-1,i,...,j的多边形的最优三角剖分值
        s[i][j]表示顶点为i-1,i,...,j的多边形的最优三角剖分方法,剖分点为s[i][j]
        退化情况1:s[i][j]==i   剖分成 三角形i-1,i,j    和 多边形i,...,j
        退化情况2:s[i][j]==j-1 剖分成 多边形i-1,...,j-1和 三角形i-1,j-1,j
        一般情况:k = s[i][j]   剖分成 多边形i-1,...,k  和 多边形 k,...,j
        权的定义:多边形的周长+剖分的弦长,所以对两种特殊情况进行了处理
    */
        for (int i = 1; i < n; i++)
            t[i][i] = 0;//只有两个顶点认为权是0
        for (int r = 2; r < n; r++)//r+1边形
        {
            for (i = 1; i <= n - r; i++)
            {
                int j = i + r -1;
                /*当i-1,i,j是相邻三个顶点时(r==2),权为
                  t[i+1][j] + Weight(dist, i-1, i, j)
                  否则,权为
                  t[i+1][j] + Weight(dist, i-1, i, j) - dist[i][j]
                  因为t[i+1][j]和eight(dist, i-1, i, j)分别计算了
                  一次dist[i][j]
                */
                t[i][j] = t[i+1][j] + Weight(dist, i-1, i, j) -
                    (r==2?0:dist[i][j]);
                s[i][j] = i;
     
                for (int k = i + 1; k < j; k++)
                {/*
                   当取剖分i-1,j-1时权为
                   t[i][k] + t[k+1][j] + dist[i-1][j] + dist[k][j]
                   因为t[k+1][j]退化,权为0,故把边dist[k][j]补上
                   否则权为t[i][k] + t[k+1][j] + dist[i-1][j]
                 */
                    float u = t[i][k] + t[k+1][j] + dist[i-1][j] +
                        (k+1==j?dist[k][j]:0);
                    if (u<t[i][j])
                    {
                        t[i][j] = u;
                        s[i][j] = k;
                    }
                }
            }
        }
    }
     
    void    ShowSolution1(int s[][V], int i, int j)
    {
        if (i + 1 >= j)    return;
        int k = s[i][j];
     
        if (k == i)
        {//退化情况1:s[i][j]==i   剖分成 三角形i-1,i,j    和 多边形i,...,j
            cout<<'('<<i<<','<<j<<") ";
            ShowSolution1(s, i+1, j);
        }
        else
            if (k==j-1)
            {//退化情况2:s[i][j]==j-1 剖分成 多边形i-1,...,j-1和 三角形i-1,j-1,j
                ShowSolution1(s, i, j-1);
                cout<<'('<<i-1<<','<<j-1<<") ";
            }
            else
            {//一般情况:k = s[i][j]   剖分成 多边形i-1,...,k  和 多边形 k,...,j
                ShowSolution1(s, i, k);
                cout<<'('<<i-1<<','<<k<<") ";
                cout<<'('<<k<<','<<j<<") ";
                ShowSolution1(s, k+1, j);
            }
    }
     
    float    Distance(float dist[][V], int i, int j)
    {
        if (i == (j + 1)%V || j == (i +1)%V)
            return 0;
        return dist[i][j];
    }
     
    void    minWeightTriangulation2(int n, float dist[][V], float t[][V+1], int s[][V+1])
    {
    /*
       t[i][j]表示从顶点i开始的j个顶点围成的多边形(j边形)的最优剖分的权
       s[i][j]表示从顶点i开始的j个顶点围成的多边形(j边形)的最优剖分的方法,
       剖分点为 i + s[i][j]
       退化情况1:s[i][j]==1  剖分成 三角形i,i+1,i+j-1 和 多边形 i+1,...,i+j-1
       退化情况2:s[i][j]==j-2剖分成 多边形i,...,i+j-2 和 三角形 i,i+j-2,i+j-1
       一般情况 :k = s[i][j] 剖分成 多边形i,...,i+k   和 多边形 i+k,...,i+j-1
     */
        const    MAX    =    10000;
        float    temp, q;
        int    kk;
         
        for (int k = 0; k < n; k++)
        {
            t[k][2] = 0;
            t[k][3] = 0;
        }
     
        for (int r = 4; r <= n; r++)
            for (int i = 0; i < n; i++)
            {
                for (q = MAX, kk = 1; kk <= r - 2; kk++)
                {/*
                   划分成子问题 
                   多边形i,...,i+kk 和 多边形 i+kk,...,i+r-1
                   划分弦为 (i, ((i+kk)%n) 和 ((i+kk)%n, (i+r-1)%n)
                   由于Distance函数中相邻弦长度为0,故退化情况自动包含
                     */
                    temp = t[i][(kk+1)%n] + t[(i+kk)%n][(n+r-kk)%n] + 
                        Distance(dist, i, ((i+kk)%n) ) +  
                        Distance(dist, (i+kk)%n, (i+r-1)%n);
                    if (temp < q)
                    {
                        k = kk;
                        q = temp;
                    }
                }
                t[i][r] = q;
                s[i][r] = k;
                if (r==n) break;//一旦r==n可以马上跳出本层循环
            }
    }
     
    void    ShowSolution2(int s[][V+1], int i, int j)
    {
        if (j<=3)    return;
     
        int k = s[i][j];
        if  (k==1)
        {//退化情况1:s[i][j]==1  剖分成 三角形i,i+1,i+j-1 和 多边形 i+1,...,i+j-1
            cout<<'('<<i+1<<','<<i+j-1<<") ";
            ShowSolution2(s, i+1, j-1);
        }
        else
            if (s[i][j]==j-1)
            {//退化情况2:s[i][j]==j-2剖分成 多边形i,...,i+j-2 和 三角形 i,i+j-2,i+j-1
                cout<<'('<<i<<','<<i+j-1<<") ";
                ShowSolution2(s, i, j-1);
            }
            else
            {//一般情况 :k = s[i][j] 剖分成 多边形i,...,i+k   和 多边形 i+k,...,i+j-1
                ShowSolution2(s, i, k+1);
                cout<<'('<<i<<','<<i+k<<") ";
                ShowSolution2(s, i+k, j-k);
                cout<<'('<<i+k<<','<<i+j-1<<") ";
            }
    }
  • 相关阅读:
    题解报告:hdu1995汉诺塔V(递推dp)
    黑色CSS3立体动画菜单
    jQuery计算器插件
    CSS3动画库animate.css
    缩略图悬浮效果的jQuery焦点图
    CSS伪元素实现的3D按钮
    CSS3 3D旋转按钮对话框
    jQuery仿Android锁屏图案应用
    jQuery横向图片手风琴
    jQuery滑动杆打分插件
  • 原文地址:https://www.cnblogs.com/mjgw/p/12437296.html
Copyright © 2011-2022 走看看