【问题标题】:Fibonacci Boxes斐波那契盒子
【发布时间】:2013-08-09 20:43:59
【问题描述】:

我知道堆栈溢出和一般网络上有很多斐波那契问题和答案,但这是一个困扰我一段时间的问题,我似乎无法破解它或找到解决方案。

创建斐波那契算法很容易,其中有很多,但我正在尝试使用 C# 以图形方式创建螺旋形的盒子。这不适用于 Uni 或其他任何东西,这只是一个我花了太多时间解决的问题,我现在需要找到解决方案,如果你明白我的意思吗?

这是我目前所拥有的,现在我确实有了更好的配置,但是经过无数小时的修改代码,这就是我目前所拥有的:

public partial class Form1 : Form
{
    public const int FIBNUM = 6;
    public const int CENTRE = 10;
    public const int SIZE = 10;
    public const int OFFSET = 100;

    public Form1()
    {
        InitializeComponent();

        drawSpiral();
    }

    private int fib(int n)
    {
        switch (n)
        {
            case 0:
                return 0;
            case 1:
                return 1;
            default:
                return fib(n - 1) + fib(n - 2);
        }
    }

    private void drawSpiral()
    {
        if (pictureBox1.Image == null)
        {
            pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        }

        using (Graphics g = Graphics.FromImage(pictureBox1.Image))
        {
            Rectangle r = new Rectangle(0, 0, 0, 0);

            int fibnum = 0;
            int centre = 0;
            int size = 0;
            int cnt = 0;

            for (int n = 1; n <= FIBNUM; n++)
            {
                fibnum = fib(n);
                centre = fibnum * CENTRE;
                size = fibnum * SIZE;

                ++cnt;
                if (cnt == 1)
                {
                    if (n == 1)
                    {
                        r = new Rectangle(fibnum + OFFSET, fibnum + OFFSET, size, size);
                        g.DrawRectangle(Pens.Red, r);

                        r = new Rectangle((fibnum + size) + OFFSET, fibnum + OFFSET, size, size);
                        g.DrawRectangle(Pens.Purple, r);

                        n++;
                    }
                    else
                    {
                        r = new Rectangle((centre - size) + OFFSET, (centre - size) + OFFSET, size, size);        
                        g.DrawRectangle(Pens.Black, r);
                    }
                    continue;
                }
                if(cnt == 2)
                {
                    r = new Rectangle((fibnum) + OFFSET, (fibnum - size) + OFFSET, size, size);
                    g.DrawRectangle(Pens.Blue, r);
                    continue;
                }
                if (cnt == 3)
                {
                    r = new Rectangle((fibnum - size) + OFFSET, (fibnum - size) + OFFSET, size, size);
                    g.DrawRectangle(Pens.Green, r);

                    continue;
                }
                if (cnt == 4)
                {
                    r = new Rectangle((fibnum - size / 2) + OFFSET, (fibnum - size) + OFFSET, size, size);
                    g.DrawRectangle(Pens.Gray, r);
                }
                cnt = 0;       
            }
        }
        pictureBox1.Invalidate();
    }

我从 wikipedia 中获取了我正在尝试以图形方式创建的图像:

提前致谢。

【问题讨论】:

  • 1.您的实际问题是什么? 2.你能给我们一些我们可以运行的代码(没有 UI)如果这是一个 UI 的东西?
  • 绘图部分有问题吗?将盒子连接在一起?

标签: c# winforms fibonacci


【解决方案1】:

给你:

public partial class Form1 : Form
{
    public const int FIBNUM = 8;
    public const int CENTERX = 300;
    public const int CENTERY = 300;
    public const int ZOOM = 10;

    public Form1()
    {
        InitializeComponent();
        drawSpiral();
    }

    private int fib(int n, int p = 0, int q = 1)
    {
        switch (n)
        {
            case 0: return 0;
            case 1: return q;
            default: return fib(n - 1, q, p + q);
        }
    }

    private void drawSpiral()
    {
        if (pictureBox1.Image == null)
        {
            pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        }

        using (Graphics g = Graphics.FromImage(pictureBox1.Image))
        {
            Rectangle r = new Rectangle(0, 0, 0, 0);

            int x = CENTERX;
            int y = CENTERY;

            for (int n = 1; n <= FIBNUM; n++)
            {
                int fibnum = fib(n)*ZOOM;

                r = new Rectangle(x, y, fibnum, fibnum);
                g.DrawRectangle(Pens.Red, r);

                switch (n % 4)
                {
                    case 0:
                        {
                            y += fibnum;
                            break;
                        }
                    case 1:
                        {
                            x += fibnum;
                            y -= fib(n - 1) * ZOOM;
                            break;
                        }
                    case 2:
                        {
                            x -= fib(n - 1)*ZOOM;
                            y -= fib(n + 1)*ZOOM;
                            break;
                        }
                    case 3:
                        {
                            x -= fib(n + 1) * ZOOM;
                            break;
                        }
                }
            }
            pictureBox1.Invalidate();
        }
    }
}

请注意,我已将您的斐波那契函数更改为性能更好的函数;特别是,我的计算线性时间的下一个斐波那契数。 使用一些 MatheMagic (抱歉开了个玩笑 :))你可以让它变得更聪明,并获得

    private int move(int n, int a, int currentFib)
    {
        switch (a)
        {
            case 1: return currentFib;
            case 2: return -fib(n - 1) * ZOOM;
            case 3: return -fib(n + 1) * ZOOM;
            default: return 0;
        }
    }

    private void drawSpiral()
    {
        if (pictureBox1.Image == null)
        {
            pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        }

        using (Graphics g = Graphics.FromImage(pictureBox1.Image))
        {
            Rectangle r = new Rectangle(0, 0, 0, 0);

            int x = CENTERX;
            int y = CENTERY;

            for (int n = 1; n <= FIBNUM; n++)
            {
                int fibnum = fib(n)*ZOOM;

                r = new Rectangle(x, y, fibnum, fibnum);
                g.DrawRectangle(Pens.Red, r);

                x += move(n, n % 4, fibnum);
                y += move(n, (n + 1) % 4, fibnum);
            }
            pictureBox1.Invalidate();
        }
    }

【讨论】:

    【解决方案2】:
    private int fib(int n)
    {
        switch (n)
        {
            case 0:
                return 0;
            case 1:
                return 1;
            default:
                return fib(n - 1) + fib(n - 2);
        }
    }
    

    这已经够慢了,也许在这个任务中没关系,但使用数组fib[1..n] (fib[0]=0 fib[1]=1 for(i = 2;i&lt;=n;i++)fib[i]=fib[i-1]+fib[i-2]) 不是更好,它可以在O(n) 中工作O(n*(1.7^n))

    【讨论】:

      【解决方案3】:

      我认为你的代码太复杂了,因为你试图一次做很多事情。考虑以下代码,其中螺旋线围绕原点绘制,没有缩放和平移:

      // the current fibonacci numbers
      int current = 1;
      int previous = 0;
      
      // the current bounding box
      int left = 0;
      int right = 1;
      int top = 0;
      int bottom = 0;
      
      // the number of boxes you want to draw
      const int N = 10;
      
      for (int i = 0; i < N; i++) {
          switch (i % 4) {
              case 0: // attach to bottom of current rectangle
                  drawRectangle(g, left, right, bottom, bottom + current);
                  bottom += current;
                  break;
              case 1: // attach to right of current rectangle
                  drawRectangle(g, right, right + current, top, bottom);
                  right += current;
                  break;                
              case 2: // attach to top of current rectangle
                  drawRectangle(g, left, right, top - current, top);
                  top -= current;
                  break; 
              case 3: // attach to left of current rectangle
                  drawRectangle(g, left - current, left, top, bottom);
                  left -= current;
                  break; 
          }
      
          // update fibonacci number
          int temp = current;
          current += previous;
          previous = temp;
      }
      

      然后您可以在单独的方法drawRectangle 中处理实际的绘图部分(我省略了有关实际图形对象的所有细节,但您可以自己做)。

      const int SCALE = 5;
      const int OFFSET = 150;
      
      private void drawRectangle(Graphics g, int left, int right, int top, int bottom)
      {
          g.DrawRectangle(Pens.Red, new Rectangle(SCALE * left + OFFSET, 
                                                  SCALE * top + OFFSET, 
                                                  SCALE * (right - left),
                                                  SCALE * (bottom - top)));
      }
      

      输出:

      【讨论】:

      • 谢谢,经过一些调整和改变,我想我现在已经完全得到了我所追求的;)
      • @DraconianTimes 你是对的。我现在将right 初始化为1 并且输出是正确的,此外,我添加了一些缩放以创建更好的图片(参见打印屏幕)
      • 完美!我稍微调整了一下,但这正是我想要实现的。不知道我会试着把金色螺旋放在盒子里,也许太难了哈哈
      猜你喜欢
      • 2012-12-29
      • 1970-01-01
      • 2015-06-05
      • 2014-05-23
      • 2011-11-27
      • 2013-03-31
      • 2014-05-03
      • 2010-12-03
      • 2011-09-19
      相关资源
      最近更新 更多