蛮力法04

——进步基于积累。

 

最小凸包问题:

平面上有n个点p1,p2, ..., pn, 要求求出一个面积最小的凸多边形,使得这个多边形包含所有平面上的点。

分析:

ptList[n] n>2

for i=0,to n

{

    for j=i+1, to n

    {

         //判断其他所有的点是否都在该直线的一边

         //if 所有的点都在线的一边,则说明是凸边,可记录,否则退出循环

         //判断点和线的关系,可以通过线解析方程,也可以通过向量叉积计算

         f(x,y) (直线方程)=ax+by+c

         bool isEnvelope = true;

         int flag = 0; //在直线上

         for k=0, t0 n

         {

              int tempFlag = f(ptList[i],ptList[j])

              if tempFlag == 0

                      continue;//在直线上不予处理

              if flag == 0

              {

                      flag = tempFlag;

                      continue;

              }

              if flag * tempFlag < 0

             {

                     isEnvelope = false;       

                     break;

             }

         }

 

         if isEnvelope == true //是凸边

         {

                //进行处理

         }

    }

}

 

/// <summary>
/// 计算凸包
/// </summary>
class EnvelopeCompute
{
    private int imgWidth;
    private int imgHeight;
    private int createCount;
    private List<Point> ptLst;
    private readonly int radius;
 
    public int CreateCount
    {
        set
        {
            this.createCount = value;
        }
    }
 
    public EnvelopeCompute(int width, int height, int count)
    {
        this.imgWidth = width;
        this.imgHeight = height;
        this.createCount = count;
        
        this.ptLst = new List<Point>();
        this.radius = 2;
    }
 
 
    /// <summary>
    /// 获取随机生成点的图片
    /// </summary>
    /// <returns>图片</returns>
    public Image GetRandomImag()
    {
        //随机产生点
        RandomCratePtLst();
        //绘制图片
        Bitmap map = new Bitmap(this.imgWidth, this.imgHeight);
        Graphics gfx = Graphics.FromImage(map);
        gfx.Clear(Color.Gray);
 
        foreach (Point item in this.ptLst)
        {
            //map.SetPixel(item.X, item.Y, Color.Red);
            gfx.FillEllipse(Brushes.Red, item.X - radius, item.Y - radius, radius * 2, radius * 2);
        }
 
        gfx.Dispose();            
 
        return map;
    }
 
    /// <summary>
    /// 获取凸包结果图片
    /// </summary>
    /// <returns>结果图片</returns>
    public Image GetEnvelopeResult()
    {
        if (this.ptLst.Count < 2)
        {
            return null;
        }
 
        int leftIndex = -1;
        int rightIndex = -1;
        List<LineSegment> lines = ComputerEnvelope(ref leftIndex, ref rightIndex);
 
        Bitmap map = new Bitmap(this.imgWidth, this.imgHeight);
        Graphics gfx = Graphics.FromImage(map);
        gfx.Clear(Color.White);
 
        Pen pen = new Pen(Color.Green, 3);
        //绘制凸包
        foreach (LineSegment item in lines)
        {
            gfx.DrawLine(pen, item.StartPt, item.EndPt);
        }
 
        foreach (Point item in this.ptLst)
        {
            //map.SetPixel(item.X, item.Y, Color.Red);
            gfx.FillEllipse(Brushes.Red, item.X - radius, item.Y - radius, radius * 2, radius * 2);
        }
 
        gfx.Dispose();
        return map;
    }
 
    //随机生成点
    private void RandomCratePtLst()
    {
        this.ptLst.Clear();
 
        Random rd = new Random();
        for (int i = 0; i < this.createCount; i++)
        {
            this.ptLst.Add(new Point(rd.Next(100, this.imgWidth-100), rd.Next(100, this.imgHeight-100)));
        }
    }
 
    //蛮力计算凸包
    private List<LineSegment> ComputerEnvelope(ref int leftIndex, ref int rightIndex)
    {
        List<LineSegment> lines = new List<LineSegment>();
        //遍历每一个点和另一个点组成的线段
        for (int i = 0; i < ptLst.Count; i++)
        {
            //确保两点之间不重复
            for (int j = i + 1; j < ptLst.Count; j++)
            {
                //构建该线段方程ax+by+c=0
                int a = ptLst[j].Y - ptLst[i].Y;
                int b = ptLst[i].X - ptLst[j].X;
                int c = ptLst[j].X * ptLst[i].Y - ptLst[i].X * ptLst[j].Y;
                //遍历其他点是否在该线段的同一方向,如果是在直线上不予处理
                int flag = 0; //标记0:在线上。
                bool isEvelope = true; //标记是否是凸包边界
                for (int k = 0; k < ptLst.Count; k++)
                {
                    if (k == i || k == j)
                    {
                        continue;
                    }
                    //int temp=f(x,y)=ax+by+c
                    //if temp==0 (x,y)在线上,if temp>0 (x,y)在线一侧 if temp<0 (x,y)在线的另一侧
                    int temp = a * ptLst[k].X + b * ptLst[k].Y + c;
                    if (temp == 0)
                    {
                        continue;
                    }
 
                    if (flag == 0)
                    {
                        flag = temp;
                        continue;
                    }
 
                    if (flag * temp < 0) //在线的两端
                    {
                        isEvelope = false;
                        break;
                    }
                }
 
                //如果确实是在同一方向,则加入判断点内
                if (isEvelope)
                {
                    LineSegment segment = new LineSegment();
                    segment.StartPt = ptLst[i];
                    segment.EndPt = ptLst[j];
                    lines.Add(segment);
                }
            }
        }
 
        return lines;            
    }
 
    /// <summary>
    /// 线段
    /// </summary>
    class LineSegment
    {
        public Point StartPt;
        public Point EndPt;
    }
}

image      image

你可能感兴趣的:(蛮力法04)