界面很简单,只有一个"Button1"按钮,按下按钮后,自动开始移动大圆容器内的小圆,到局部最小值如果不满足条件,则为势能最大或势能最小的圆寻找一个随机位置重新进行计算和移动圆的位置,该算法的思想来自于黄文奇、许如初编写的《近世计算理论导引----NP难问题的背景、前景及其解算法研究》 Page 62。
- using System;
- using System.IO;
- using System.Collections;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Linq;
- using System.Text;
- using System.Windows.Forms;
- using System.Threading;
- // Form1.cs Packing Problem
- namespace PackingOb1
- {
- public partial class Form1 : Form
- {
- // 势能
- // 渐进移动的步长
- double Step;
- Circle[] circles = new Circle[10];
- StreamReader sr = new StreamReader("circles1.txt");
- string line;
- int Num;
- string[] r_str = new string[100];
- string[] co_str = new string[200];
- double[] radius = new double[100];
- PointF[] cordinates = new PointF[100];
- public Form1()
- {
- InitializeComponent();
- }
- void DrawCircle(Circle circle)
- {
- Graphics g = Graphics.FromHwnd(this.Handle);
- g.TranslateTransform(this.Width / 2, this.Height / 2);
- g.DrawEllipse(new Pen(Color.Black), new RectangleF((float)(circle.x - circle.r), (float)(circle.y - circle.r), (float)(2 * circle.r), (float)(2 * circle.r)));
- g.Dispose();
- }
- void ReadStream(StreamReader sr)
- {
- line = sr.ReadLine();
- Num = Convert.ToInt32(line); // This is a Covert Class
- line = sr.ReadLine();
- r_str = line.Split(new char[] { ' ' }); // Pay attention to the use of the Split
- for (int i = 0; i < Num; i++)
- {
- radius[i] = Convert.ToDouble(r_str[i]);
- }
- line = sr.ReadLine();
- co_str = line.Split(new char[] { ' ' });
- for (int i = 0; i < Num; i++)
- {
- cordinates[i].X = (float)Convert.ToDouble(co_str[2 * i]);
- cordinates[i].Y = (float)Convert.ToDouble(co_str[2 * i + 1]);
- }
- }
- private void Form1_Load(object sender, EventArgs e)
- {
- // 将数据从文本文件中读取出来,创建圆形
- ReadStream(sr);
- for (int i = 0; i < Num; i++)
- {
- circles[i] = new Circle();
- circles[i].r = radius[i];
- circles[i].x = cordinates[i].X;
- circles[i].y = cordinates[i].Y;
- }
- }
- /// <summary>
- /// 计算整个系统的势能,同时计算最大势能的点max_PE和最小势能的点min_PE
- /// </summary>
- double calc_PE(Circle[] circles, ref Circle maxPE_circle, ref Circle minPE_circle)
- {
- double PE = 0;
- // 计算前,将以前的计算结果清零!!!
- for (int i = 1; i < Num; i++)
- {
- circles[i].dx = 0;
- circles[i].dy = 0;
- circles[i].PE = 0;
- }
- calc_dx_dy(circles);
- for (int i = 1; i < Num; i++)
- {
- PE += circles[i].PE;
- }
- maxPE_circle = minPE_circle = circles[1];
- for (int i = 2; i < Num; i++)
- {
- maxPE_circle = maxPE_circle.PE < circles[i].PE ? circles[i] : maxPE_circle;
- minPE_circle = minPE_circle.PE > circles[i].PE ? circles[i] : minPE_circle;
- }
- return PE;
- }
- /// <summary>
- /// 统计所有圆的dx 与dy
- /// </summary>
- void calc_dx_dy(Circle[] circles)
- {
- for (int i = 1; i < Num; i++)
- {
- MoveDirection(circles[i], Num, circles, i);
- }
- }
- /// <summary>
- /// 计算每个圆要移动的方向
- /// </summary>
- /// <param name="circle"></param>
- /// <param name="Num"></param>
- /// <param name="numth"></param>
- void MoveDirection(Circle circle, int Num, Circle[] circles, int numth)
- {
- for (int i = 0; i < Num; i++)
- {
- // 考虑与第0个圆的距离
- if (i == 0)
- {
- double d0i = Math.Sqrt(circle.x * circle.x + circle.y * circle.y);
- if (d0i + circle.r > circles[i].r)
- {
- circle.dx += circle.x / d0i * (d0i + circle.r - circles[i].r);
- circle.dy += circle.y / d0i * (d0i + circle.r - circles[i].r);
- circle.PE += Math.Pow(d0i + circle.r - circles[i].r, 2.0);
- }
- }
- // 考虑容器内与其他圆的距离
- else if (numth != i)
- {
- double dij = Math.Sqrt(Math.Pow(circle.x - circles[i].x, 2.0) + Math.Pow(circle.y - circles[i].y, 2.0));
- if (dij < circle.r + circles[i].r)
- {
- circle.dx += (circles[i].x - circle.x) / dij * (circle.r + circles[i].r - dij);
- circle.dy += (circles[i].y - circle.y) / dij * (circle.r + circles[i].r - dij);
- circle.PE += Math.Pow(circle.r + circles[i].r - dij, 2.0);
- }
- }
- }
- }
- private void Form1_Paint(object sender, PaintEventArgs e)
- {
- for (int i = 0; i < Num; i++)
- {
- DrawCircle(circles[i]);
- }
- }
- /// <summary>
- /// 单击,圆开始移动
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void button1_Click(object sender, EventArgs e)
- {
- Step = 0.1;
- Circle oldmaxPE = circles[0];
- Circle maxPE = circles[1];
- Circle minPE = circles[1];
- double New_PE;
- double Old_PE = 0;
- int t = 0;
- while (true)
- {
- if (Step >= 0.001)
- {
- New_PE = calc_PE(circles, ref maxPE, ref minPE);
- if (New_PE < 0.0001)
- {
- return;
- }
- else if (New_PE < Old_PE)
- {
- Old_PE = New_PE;
- for (int i = 1; i < Num; i++)
- {
- circles[i].x -= Step * circles[i].dx;
- circles[i].y -= Step * circles[i].dy;
- }
- Invalidate();
- Update();
- //Thread.Sleep(10);
- }
- else if (New_PE >= Old_PE)
- {
- Old_PE = New_PE;
- Step = 0.8 * Step;
- for (int i = 0; i < Num; i++)
- {
- circles[i].x -= Step * circles[i].dx;
- circles[i].y -= Step * circles[i].dy;
- }
- Invalidate();
- Update();
- //Thread.Sleep(10);
- }
- }
- else
- {
- if (maxPE == oldmaxPE)
- {
- t = t + 1;
- }
- if (t < 1)
- {
- // 在圆盘上随机选点,重新摆放势能最大的圆
- // 注意此时的maxPE 和 oldmaxPE均指向old_Circles中的对象。
- Random rand = new Random();
- maxPE.x = -circles[0].r + 2 * circles[0].r * rand.NextDouble();
- maxPE.y = -circles[0].r + 2 * circles[0].r * rand.NextDouble();
- oldmaxPE = maxPE;
- Step = 0.1;
- }
- else if (t == 1)
- {
- Random rand = new Random();
- minPE.x = -circles[0].r + 2 * circles[0].r * rand.NextDouble();
- minPE.y = -circles[0].r + 2 * circles[0].r * rand.NextDouble();
- t = 0;
- oldmaxPE = circles[0];
- Step = 0.1;
- }
- }
- }
- }
- }
- /// <summary>
- /// 一个圆 接受坐标(x, y)和半径r
- /// </summary>
- public class Circle
- {
- // 圆的坐标
- public double x;
- public double y;
- // 圆的半径
- public double r;
- // 要移动的方向
- public double dx;
- public double dy;
- public double PE;
- /// <summary>
- /// 创建一个圆(不用参数)
- /// </summary>
- public Circle()
- {
- this.dx = 0;
- this.dy = 0;
- this.PE = 0;
- }
- /// <summary>
- /// 创建一个圆
- /// </summary>
- /// <param name="x"></param>
- /// <param name="y"></param>
- /// <param name="r"></param>
- public Circle(double x, double y, double r)
- {
- this.x = x;
- this.y = y;
- this.r = r;
- this.dx = 0;
- this.dy = 0;
- this.PE = 0;
- }
- /// <summary>
- /// 拷贝复制该Circle
- /// </summary>
- /// <returns>返回Circle</returns>
- public Circle Clone()
- {
- Circle clone_Circle = new Circle();
- clone_Circle.x = this.x;
- clone_Circle.y = this.y;
- clone_Circle.r = this.r;
- clone_Circle.dx = this.dx;
- clone_Circle.dy = this.dy;
- clone_Circle.PE = this.PE;
- return clone_Circle;
- }
- }
- }