软件设计师考试经典基础算法(分治法、回溯法、动态规划法、贪心法、堆排序、归并排序)含有详细注释

 所有代码和注释都是本人逐个敲出来,参考了软件设计师考试指导教材里的C代码,现全部改用C#编写。如有问题,欢迎留言探讨。

https://gitee.com/elite216/algorithms/blob/master/Form1.cs

   1 public partial class Form1 : Form
   2     {
   3         static int N = 12;
   4         int[] b = new int[N + 1];  //用于标记1-N这些数字是否已经被使用(方格填数问题)
   5         int[] a = new int[10];    //方格填数问题
   6         //checkMatrix矩阵用于方格填数问题,{5,7,-1}表示所填的数要与5、7两个位置的数比较
   7         //{-1,-1,-1}表示不需要与任何数比较
   8         int[,] checkMatrix = { { -1, -1, -1 }, { 0, -1, -1 }, { 1, -1, -1 }, 
   9                                    { 0, -1, -1 }, {1,3,-1},{2,4,-1},
  10                                    {3,-1,-1},{4,6,-1},{5,7,-1}};
  11 
  12         int[] deltai = { 2, 1, -1, -2, -2, -1, 1, 2 };  //用于马的遍历问题
  13         int[] deltaj = { 1,2,2,1,-1,-2,-2,-1 };         //用于马的遍历问题
  14         int[,] board = new int[8, 8];                   //用于马的遍历问题,标记棋盘各坐标是否已用
  15 
  16 
  17         public Form1()
  18         {
  19             InitializeComponent();
  20         }
  21 
  22         private int [] GetNext(string pstr)  //获取模式串的next数组
  23         {
  24             int len=pstr.Length;        //模式串的长度
  25             
  26             string[] arr=new string[len];   //模式串各字符数组
  27 
  28             int[] next = new int[len+1];   //next函数数组,多取一位避免while循环时溢出
  29 
  30             for (int k = 0; k < len; k++)
  31             {
  32                 arr[k] = pstr.Substring(k,1);  //模式串字符数组赋值
  33             }
  34 
  35             next[0] = -1;  //赋初始值
  36             int j = -1;
  37             int i = 0;
  38 
  39             while (i < len)
  40             {
  41                 if (j == -1 || arr[i] == arr[j]) { ++i; ++j; next[i] = j; }  //字符串第i字符和第i-1字符相同,i、j都加1
  42                 else j = next[j];   //否则重新设置j的开始值
  43             }
  44 
  45             for (int k = 0; k < arr.Length; k++)  //显示模式串及其next函数值
  46             {
  47                 if (k == 0) { label1.Text = "原字符串:"; label2.Text = "next函数值:"; }
  48                 label1.Text += arr[k];
  49                 label2.Text += next[k].ToString()+"";
  50             }
  51             return next;
  52         }
  53 
  54         private void button2_Click(object sender, EventArgs e)  //主串与模式串比较
  55         {
  56             string mstr = textBox2.Text;  //主串
  57             int mlen = mstr.Length;       //主串长度
  58             string[] marr = new string[mlen];  //主串字符数组
  59             for (int k = 0; k < mlen; k++)      //主串数组赋值
  60             {
  61                 marr[k] = mstr.Substring(k,1);  //把字符串中的字符逐个分解至数组中
  62             }
  63 
  64             int[] next = GetNext(textBox1.Text);  //获得next函数值
  65 
  66             string pstr=textBox1.Text;  //获得输入的模式串
  67             int plen = pstr.Length;     //模式串的长度
  68             string [] parr=new string[plen]; //模式串字符数组 
  69 
  70             for (int k = 0; k < plen; k++)      //模式串数组赋值
  71             {
  72                 parr[k] = pstr.Substring(k,1);
  73             }          
  74 
  75             int i = -1;
  76             int j = -1;
  77             while (i < mlen && j < plen)
  78             {
  79                 if (j == -1 || marr[i] == parr[j]) { ++i; ++j; }
  80                 else { j = next[j]; }
  81             }
  82             if (j >= plen) label5.Text = "模式串存在,位于" + (i - plen).ToString();   //i-plen是模式串位于主串的位置(起始位置)
  83             else label5.Text = "模式串不存在!";
  84         }
  85 
  86         private void button3_Click(object sender, EventArgs e)//迭代二分查找法求方程的根
  87         {
  88             double i = this.mycuba(0.00001, 1.0, 2.0);
  89             MessageBox.Show(i.ToString(), "j=", MessageBoxButtons.OK);
  90         }
  91         private double mycuba(double f, double a, double b) //二分查找法解方程
  92         {
  93             double i = a + (b - a) / 2;
  94             while (System.Math.Abs(i * i * i-5) > f)
  95             {
  96                 if (i * i * i - 5 > 0)
  97                 {
  98                     b =a+ (b - a) / 2;
  99                 }
 100                 else
 101                 {
 102                     a = a+ (b - a) / 2;
 103                 }
 104                 i = a + (b - a) / 2;
 105                // MessageBox.Show(i.ToString(), "i=", MessageBoxButtons.OK);
 106             }
 107             return i;
 108         }
 109 
 110         private void merge(int [] A,int p, int q, int r) //分治法归并排序的归并
 111         {
 112             //pa(a,"a");
 113             MessageBox.Show("P="+p.ToString()+",Q="+q.ToString()+",R="+r.ToString(),"合并", MessageBoxButtons.OK);
 114             pa(A, "A数列的值");
 115             int n1 = q - p + 1;
 116             int n2 = r - q;
 117             int i, j, k;
 118             int[] L = new int[50];
 119             int[] R = new int[50];
 120             for (i = 0; i < n1; i++)
 121             {
 122                 L[i] = A[p+i];
 123             }
 124             
 125             for (i = 0; i < n2; i++)
 126             {
 127                 //MessageBox.Show(i.ToString(), "右侧i值", MessageBoxButtons.OK);
 128                 R[i] = A[q +1+ i];
 129             }
 130             //MessageBox.Show(n1.ToString(), "n1值", MessageBoxButtons.OK);
 131             L[n1] = 100;
 132             
 133             R[n2] = 100;
 134            // pa(L, "左侧");
 135 
 136             i = 0;
 137             j = 0;
 138             //pa(R, "右侧");
 139 
 140             for (k = p; k < r + 1; k++)
 141             {
 142                 if (L[i] < R[j])
 143                 {
 144                     A[k] = L[i];
 145                     i++;
 146                 }
 147                 else
 148                 {
 149                     A[k] = R[j];
 150                     j++;
 151                 }               
 152             }
 153             //pa(a, "归并后的a");
 154         }
 155         private void mergesort(int[] A, int p, int r)  //分治法归并排序
 156         {
 157             int q;
 158             
 159             if (p < r)
 160             {
 161                 q = (p + r) / 2;
 162                // MessageBox.Show("p="+p.ToString(), "排序中的q="+q.ToString(), MessageBoxButtons.OK);
 163                 mergesort(A, p, q);//排序前半
 164                 mergesort(A, q+1, r); //排序后半
 165                 merge(A, p, q, r); //两半归并
 166             }
 167             
 168         }
 169 
 170         private void button4_Click(object sender, EventArgs e)  //分治排序主程序
 171         {
 172             int [] a={ 7,4,9,8,10,2,3,11,55,23};
 173             mergesort(a, 0, 9);
 174             pa(a,"final");
 175         }
 176 
 177         private  void pa(int[] a, string b)  //通用方法,用于显示数组
 178         {
 179             string s = "";
 180             for (int i = 0; i < a.Length; i++)
 181             {
 182                 s = s + a[i].ToString()+"";
 183             }
 184             s = s.Substring(0, s.Length - 1);
 185             MessageBox.Show(b, "q=" + s.ToString(), MessageBoxButtons.OK);
 186         }
 187 
 188         private void button5_Click(object sender, EventArgs e)  //0-1背包问题的动态规划法,主程序
 189         {
 190             int n=5, W=17; //n是物品数量,W是背包能装的总重量
 191             int[] weights = {2,2,6,5,4};  //物品的重量
 192             int[] values = {6,3,5,4,6};     //物品的价值
 193             int []x=new int [n];           //x数组,用0表示不装某物品,1表示装入某物品
 194             int[,] c = new int[n, W];       //二维数组,相当于创建表格,后续填表
 195             c = pack(n, W, weights, values);
 196             int i;
 197             for (i = n; i > 1; i--)
 198             {
 199                 if (c[i, W] == c[i - 1, W])
 200                 {
 201                     x[i - 1] = 0;
 202                 }
 203                 else
 204                 {
 205                     x[i - 1] = 1;
 206                     W = W - weights[i - 1];
 207                 }
 208             }
 209             if (c[1, W] == 0)
 210             {
 211                 x[0] = 0;
 212             }
 213             else
 214             {
 215                 x[0] = 1;
 216             }
 217             pa(x, "背包");  //显示结果
 218 
 219         }
 220         private int[,] pack(int n, int W, int[] weights, int[] value)  //填表
 221         {
 222             int i, w;
 223             int [ ,] c=new int [n+1,W+1];
 224             for (w = 0; w <= W; w++) 
 225             {
 226                 c[0, w] = 0;  //首列都为0
 227             }
 228             for (i = 1; i <= n; i++)
 229             {
 230                 c[i, 0] = 0;   //首行都为0
 231                 for (w = 1; w <= W; w++) //逐行填写
 232                 {
 233                     if (weights[i - 1] <= w)  //如果背包剩余重量大于物品重量
 234                     {
 235                         if (value[i - 1] + c[i - 1, w - weights[i - 1]] > c[i - 1, w])
 236                         {
 237                             c[i, w] = value[i - 1] + c[i - 1, w - weights[i - 1]];  //放入第i-1个物品
 238                         }
 239                         else
 240                         {
 241                             c[i, w] = c[i - 1, w];  //不放入第i-1个物品
 242                         }
 243                     }
 244                     else
 245                     {
 246                         c[i, w] = c[i - 1, w];  //不放入第i-1个物品
 247                     }
 248                 }
 249             }
 250             return c;
 251         }
 252 
 253         private void button6_Click(object sender, EventArgs e)  //动态规划法最长公共子串问题
 254         {
 255             string[] x = { "A", "B", "C", "B", "D", "A","B"};
 256             string[] y = { "B", "D", "C", "A", "B", "A"};
 257             int j = x.Length;
 258             int i = y.Length;
 259             string [,] L=new string[i+1,j+1];
 260             int[,] B = new int[i + 1, j + 1];
 261             string[,] C = new string[i + 1, j + 1];
 262             B[0, 0] = 0;
 263             C[0, 0] = "※0";
 264             L[0, 0] = "";
 265             for (int ii = 1; ii <= i; ii++)
 266             {
 267                 B[ii, 0] = 0;
 268                 L[ii, 0] = "";
 269                 C[ii, 0] = "※0"+y[ii-1];
 270                 for (int jj = 1; jj <= j; jj++)
 271                 {
 272                     B[0, jj] = 0;
 273                     C[0, jj] = ""+x[jj-1];
 274                     L[0, jj] = "";
 275                     if (y[ii-1] == x[jj-1])
 276                     {
 277                         B[ii, jj] = B[ii - 1, jj - 1] + 1;
 278                         L[ii, jj] = "";
 279                         C[ii, jj] = "" + B[ii, jj].ToString();
 280                     }
 281                     else
 282                     {
 283                         if (B[ii - 1, jj] >= B[ii, jj - 1])
 284                         {
 285                             B[ii, jj] = B[ii - 1, jj];
 286                             L[ii, jj] = "";
 287                             C[ii, jj] = "" + B[ii, jj].ToString();
 288                         }
 289                         else
 290                         {
 291                             B[ii, jj] = B[ii, jj-1];
 292                             L[ii, jj] = "";
 293                             C[ii, jj] = "" + B[ii, jj].ToString();
 294                         }
 295                     }
 296                 }
 297             }
 298 
 299             int len=B[i, j];
 300             for (int f = 0; f <= j; f++)
 301             {
 302 
 303             }
 304 
 305             toDatagrid(C);
 306            
 307         }
 308 
 309         private void toDatagrid(string [,] C)  //通用函数,输出字符数组到datagridview
 310         {
 311             DataTable dt = new DataTable();
 312 
 313             for (int kk = 0; kk < C.GetLength(1); kk++)
 314                 dt.Columns.Add(kk.ToString(), typeof(string));
 315 
 316             for (int p = 0; p < C.GetLength(0); p++)
 317             {
 318                 DataRow dr = dt.NewRow();
 319                 for (int k = 0; k < C.GetLength(1); k++)
 320                     dr[k] = C[p, k];
 321                 dt.Rows.Add(dr);
 322             }
 323             dataGridView1.DataSource = dt;
 324         }
 325 
 326         private void toDatagrid2(int[,] C)  //通用函数,输出二维整数数组到datagridview
 327         {
 328             DataTable dt = new DataTable();
 329 
 330             for (int k = 0; k < C.GetLength(1); k++)
 331                 dt.Columns.Add(k.ToString(), typeof(string));
 332 
 333             for (int p = 0; p < C.GetLength(0); p++)
 334             {
 335                 DataRow dr = dt.NewRow();
 336                 for (int k = 0; k < C.GetLength(1); k++)
 337                     dr[k] = C[p,k].ToString();
 338                 dt.Rows.Add(dr);
 339             }
 340             dataGridView1.DataSource = dt;
 341         }
 342 
 343         private void toDatagrid3(double[,] C)  //通用函数,输出双精度数数组到datagridview
 344         {
 345             DataTable dt = new DataTable();
 346 
 347             for (int k = 0; k < C.GetLength(1); k++)
 348                 dt.Columns.Add(k.ToString(), typeof(string));
 349 
 350             for (int p = 0; p < C.GetLength(0); p++)
 351             {
 352                 DataRow dr = dt.NewRow();
 353                 for (int k = 0; k < C.GetLength(1); k++)
 354                     dr[k] = C[p, k].ToString();
 355                 dt.Rows.Add(dr);
 356             }
 357             dataGridView1.DataSource = dt;
 358         }
 359 
 360         private void toGrid(int [] a)   //通用函数,输出一维整数数组到datagridview
 361         {
 362             DataTable dt = new DataTable();
 363             for (int kk = 0; kk < a.Length; kk++)
 364                 dt.Columns.Add(kk.ToString(), typeof(string));
 365             for (int i = 0; i < a.Length; i++)
 366             {
 367                 DataRow dr = dt.NewRow();
 368                     dr[i] = a[i];
 369                 dt.Rows.Add(dr);
 370             }
 371             dataGridView1.DataSource = dt;
 372         }
 373 
 374         private void button7_Click(object sender, EventArgs e) //回溯法背包问题主方法
 375         {
 376             float[] values = {11,21,31,33,43,53,55,65}; //物品的价值数值:已按单位价值排序
 377             int[] weights = {1,11,21,23,33,43,45,55};  //物品的重量:已按单位价值排序
 378             float[] VW=new float [values.Length];  //物品单位重量价值:价值/重量,已从大到小排序
 379             int W = 110;  //背包总容量
 380             for (int i = 0; i < values.Length; i++)
 381             {
 382                 VW[i] = values[i] / weights[i];   //物品单位重量价值:价值/重量,已从大到小排序
 383             }
 384 
 385             int current_weight = 0;  //当前背包重量
 386             float current_profit = 0;  //当前背包价值
 387             int weight = 0;           //背包初始重量
 388             float profit = -1;         //背包初始价值
 389             int index = 0;
 390             int[] X = new int[values.Length];
 391             int[] Y = new int[values.Length];
 392 
 393             while (true)
 394             {
 395                 while (index < values.Length && current_weight + weights[index] <= W)  //深度优先,装到不能再装为止
 396                 {
 397                     current_profit += values[index];
 398                     current_weight += weights[index];
 399                     Y[index] = 1;
 400                     index++;
 401                 }
 402                 if (index >= values.Length-1)  //如果已经到达叶子结点
 403                 {
 404                     weight = current_weight;
 405                     profit = current_profit;
 406                     index = values.Length-1;
 407                     for (int k = 0; k < values.Length; k++)  //Y数组就是一个可行解
 408                     {
 409                         X[k] = Y[k];
 410                     }
 411                 }
 412                 else
 413                 {
 414                     Y[index] = 0;  //背包已装满,后续结点不再装
 415                 }
 416 
 417                 while (Bound(values, weights, VW, W, current_profit, current_weight, index) <= profit)  //可获得最大值小于现值时,回溯
 418                 {
 419                     while (index != 0  && Y[index] != 1)  //回溯到上一个选中的节点
 420                     {
 421                         index--;
 422                     }
 423                     if (index == 0)  //如果已回溯到根节点,结束所有循环
 424                     {
 425                         toGrid(X);  //将数组X作为结果输出
 426                         return;
 427                     }
 428                     Y[index] = 0;  //将该节点设为不选
 429                     current_profit -= values[index];  //减去相应价值
 430                     current_weight -= weights[index]; //减去相应重量
 431                 }
 432                 index++;
 433             }
 434             
 435         }
 436 
 437         private float Bound(float[] values, int[] weights, float[] VW, int W, float profit_gained, int weight_used, int k)  //当前背包余量下,可获得的最大价值
 438         {
 439             for (int i = k + 1; i < weights.Length; i++)  //搜索可行解
 440             {
 441                 if (weight_used + weights[i] <= W)
 442                 {
 443                     profit_gained += values[i];
 444                     weight_used += weights[i];
 445                 }
 446                 else
 447                 {
 448                     profit_gained += VW[i] * (W - weight_used);
 449                     weight_used = W;
 450                     return profit_gained;
 451                 }
 452             }
 453             return profit_gained;
 454         }
 455 
 456         private void button8_Click(object sender, EventArgs e)  //回溯法n皇后问题
 457         {
 458             int n=8;  //4X4方格
 459             int [] Column_Num=new int [n+1];   //一维数组的序号代表行,值代表列
 460             int index = 1; //代表行
 461             int answer_num=0;
 462             for (int i = 1; i <= n; i++)
 463             {
 464                 Column_Num[i] = 0; //赋初值
 465             }
 466             toGrid(Column_Num);
 467             while (index > 0)
 468             {
 469                 Column_Num[index]++;  //从第1列开始,如果回溯则在上一次的列的基础上尝试下一列
 470                 while (Column_Num[index] <= n && Place(Column_Num, index,n)==0)  //为0表示不可行
 471                 {
 472                     Column_Num[index]++;  //如果不可行移至下一列再试,Column_Num[index]的值可能超过n
 473                 }
 474                 if (Column_Num[index] <= n)  //已放至最后一列
 475                 {                  
 476                     if (index == n)  //放置最后一个皇后成功
 477                     {
 478                         answer_num++;
 479                         MessageBox.Show("完成", "完成");
 480                         toGrid(Column_Num);
 481                         return;
 482                     }
 483                     else
 484                     {
 485                         index++;  //查找下一行
 486                         Column_Num[index] = 0;
 487                     }
 488                 }
 489                 else
 490                 {
 491                     index--;  //无法放置,回溯上一行
 492                     
 493                 }
 494             }
 495             
 496         }
 497 
 498         private int Place(int [] Column,int index,int n)   //检查所放的皇后位置可不可行
 499         {
 500             int i; //代表行
 501             for(i=1;i<index;i++)  //遍历第index行之前的所有行
 502             {
 503                 int Column_differ=System.Math.Abs(Column[index]-Column[i]);  //列的差
 504                 int Row_differ=System.Math.Abs(index-i);  //行的差
 505                 if(Column[i]==Column[index] || Column_differ==Row_differ || Column[i]>n)   //行的差/列的差等于1时,表示斜线上不可行
 506                 {
 507                     return 0;  //不可行
 508                 }
 509             }
 510             return 1; //可行
 511         }
 512 
 513         private void button9_Click(object sender, EventArgs e)   //矩阵链乘问题,主方法
 514         {
 515             int[] p = { 3, 4, 30, 5, 16, 20, 25 };  //矩阵的p数组,代表A1矩阵为3X4、A2矩阵为4X30……
 516             int[,] m = new int[8,8];
 517             int[,] s = new int[8,8];
 518             for (int i = 0; i < 8; i++)
 519             {
 520                 m[i,0] = i;
 521                 s[i, 0] = i;
 522                 for (int j = 1; j < 8; j++)
 523                 {
 524                     m[i,j] = 0;
 525                     s[i,j] = 0;
 526                 }
 527             }
 528            MatrixChain(p, m, s);
 529             toDatagrid2(s);
 530             result(s,1,6);
 531         }
 532         void MatrixChain(int[] p, int[,] m, int[,] s)  //矩阵链乘问题
 533         {
 534             int N=6;  //总共N个矩阵,矩阵个数比p数组的长度少1
 535             int i, j, k, t;
 536             for ( i = 0; i <= N; i++)
 537             {
 538                 m[i,i] = 0;
 539             }
 540 
 541             for ( t = 2; t <= N; t++)  //链乘矩阵的个数,至少为2,最多为N个
 542             {
 543                 for ( i = 1; i <= N - t+1; i++)  //t个矩阵相乘,从下标为1的矩阵开始,找t个相连的矩阵
 544                 {
 545                     j = i + t -1;     // 共t个矩阵相乘,超始下标是i,终止下标就是i+t-1
 546                     m[i,j] = 1000000;  // 设置一个最大代价
 547                     for (k = i; k < j; k++)
 548                     {
 549                         int temp = m[i,k] + m[k + 1,j] + p[i - 1] * p[k] * p[j];
 550                         if (temp < m[i,j])
 551                         {
 552                             m[i,j] = temp;
 553                             s[i,j] = k;
 554                         }
 555                     }
 556                 }
 557             }
 558         }
 559 
 560         void result(int[,] s, int i, int j)  //矩阵链乘问题结果显示
 561         {
 562             
 563             if (i == j)
 564             {
 565                 label7.Text = label7.Text + "A" + i.ToString();
 566             }
 567             else
 568             {
 569                 label7.Text = label7.Text + "(";
 570                 result(s, i, s[i, j]);
 571                 result(s, s[i, j] + 1, j);
 572                 label7.Text = label7.Text + ")";
 573             }
 574             
 575         }
 576 
 577         private void button10_Click(object sender, EventArgs e)   //堆排序,主方法
 578         {
 579             int[] data = {55,60,40,10,80,65,15,5,75};
 580             int n = data.Length;
 581             for (int i =0 ; i <= n / 2 - 1; i++)
 582             {
 583                 HeapAdjust(data, i, n - 1);
 584             }
 585             HeapAdjust(data, 0, n - 1);
 586             pa(data, "大根");  //显示
 587         }
 588         private void HeapAdjust(int [] data, int s, int m)  //堆排序,组建大根堆
 589         {
 590             int tmp, j;
 591             tmp = data[s];
 592             for (j = 2 * s + 1; j <= m; j = j * 2 + 1)
 593             {
 594                 if (j < m && data[j] < data[j + 1])
 595                 {
 596                     j++;
 597                 }
 598                 if (tmp > data[j])
 599                 {
 600                     break;
 601                 }
 602                 data[s] = data[j];
 603                 s = j;
 604             }
 605             data[s] = tmp;
 606         }
 607 
 608         private void button11_Click(object sender, EventArgs e)  //n凸多边形的切割问题
 609         {
 610             int n = 6;  //多边形的边数
 611             double[,] t=new double [n,n];  //t[i,j]表示从i-1点开始至j点构成的多边形的最优权值
 612             int[,] s = new int[n, n];  //s[i,j]=k,表示由点i-1,j,k这三个点构成一个三角形
 613             for (int i = 1; i < n; i++)
 614             {
 615                 t[i, i] = 0;
 616             }
 617             for (int r = 2; r <= n; r++)  //问题规模,如t[i,j]时,j和i相隔r条边;最大可选r=n,相当于终点与起点重合
 618             {
 619                 for (int i = 1; i < n - r+1; i++)
 620                 {
 621                     int j = i + r - 1;  //距离i点最远的点的编号,当r=n时最大取值为n-1
 622                     
 623                     t[i, j] = t[i + 1, j] + weight(i - 1, i, j);
 624                     s[i, j] = i;
 625                     for (int k = i + 1; k < j; k++)
 626                     {
 627                         double temp = t[i, k] + t[k + 1, j] + weight(i - 1, k, j);
 628                         if (temp < t[i, j])
 629                         {
 630                             t[i, j] = temp;
 631                             s[i, j] = k;
 632                         }
 633                     }
 634                 }
 635             }
 636             toDatagrid2(s);     //输出最佳方案切割位置点
 637             //toDatagrid3(t);  //输出最终权值
 638         }
 639         private double weight(int i, int j, int k) //求权值
 640         {
 641             double[,] w = {{0,5,8.1,9.2,9.8,10},
 642                             {5,0,3.2,4.5,5.7,6.7},
 643                             {8.1,3.2,0,1.4,3.2,5},
 644                             {9.2,4.5,1.4,0,2,4.1},
 645                             {9.8,5.7,3.2,2,0,2.2},
 646                             {10,6.7,5,4.1,2.2,0}};
 647             if (k == 6) k = 0;    //数组从0到5编号,因此多边形的第6个点与第0点重合
 648             return w[i, j] + w[j, k] + w[i, k];
 649         }
 650 
 651         private void button12_Click(object sender, EventArgs e)  //递归回溯法:在方阵里填数,使相邻数相加为质数
 652         {
 653             //初始化数据
 654             
 655             int[,] a = new int[3, 3];  //数组,用于存放方阵里的数
 656             bool[] vis = new bool[N+1];  //标志用于记录1到10这十个数是否已经被使用
 657             for (int i = 0; i <= N; i++)
 658             {
 659                 vis[i] = false;
 660             }
 661               
 662             List<int> list = new List<int>();  //list用于记录所有结果
 663             dfs(a, 0, 0, vis, list);
 664 
 665             //输出得到的结果list
 666             string s="";
 667             for (int i = 0; i < list.Count; i++)
 668             {
 669                 s += list[i].ToString()+"";
 670                 if ((i + 1) % 9 == 0) { s = s.Substring(0, s.Length - 1) + "\n"; }
 671             }
 672             MessageBox.Show((list.Count/9).ToString(), "总共数量", MessageBoxButtons.OK, MessageBoxIcon.Information);
 673             MessageBox.Show(s, "", MessageBoxButtons.OK, MessageBoxIcon.Information);
 674         }
 675         private bool isprime(int n)  //判断一个整数是不是质数
 676         {
 677             for (int i = 2; i * i <= n; i++)
 678             {
 679                 if (n % i == 0) return false;
 680             }
 681             return true;
 682         }
 683         private bool check(int [,]a,int x, int y, int k)  //检查k跟它的上、左位置的数相加是否为质数
 684         {
 685             if (y>0 && !isprime(a[x, y - 1] + k)) return false;  //与左侧数相加不是质数
 686             if (x>0 && !isprime(a[x - 1, y] + k)) return false;  //与上方数相加不是质数
 687             return true;
 688         }
 689         private void dfs(int[,] a, int x, int y, bool[] vis, List<int> list)
 690         {
 691             if (x == 3)  //x=3说明遍历完成,开始输出数组
 692             {
 693                 for (int i = 0; i < 3; i++)
 694                 {
 695                     for (int j = 0; j < 3; j++)
 696                     {
 697                         list.Add(a[i,j]);
 698                     }
 699                 }
 700                 return;
 701             }
 702             for (int i = 1; i <= N; i++)
 703             {
 704                 if (!vis[i] && check(a, x, y, i))
 705                 {
 706                     a[x, y] = i;
 707                     vis[i] = true;
 708                     if (y == 2) dfs(a, x + 1, 0, vis,list);
 709                     else dfs(a, x, y + 1, vis,list);
 710                     a[x, y] = 0;   //回溯
 711                     vis[i] = false;    //回溯               
 712                 }
 713             }
 714         }
 715 
 716         private void button13_Click(object sender, EventArgs e)  //非递归回溯:在方阵里填数,使相邻数相加为质数
 717         {
 718             for (int i = 1; i <= N; i++)
 719             {
 720                 b[i] = 1;  //设置初值
 721             }
 722             List<int> list = new List<int>();
 723             find(list);
 724             MessageBox.Show((list.Count/10).ToString(), "结果组数", MessageBoxButtons.OK); //结果组数
 725             string s = "";
 726             for (int i = 0; i < list.Count; i++)
 727             {
 728                 s += list[i].ToString() + "";
 729             }
 730             MessageBox.Show(s, "所有结果", MessageBoxButtons.OK);
 731         }
 732 
 733         private void write(int[] a, List<int> list)   //将数组a转为list
 734         {
 735            // List<int> list = new List<int>();
 736             for (int i = 0; i < a.Length; i++)
 737             {
 738                 list.Add(a[i]);
 739             }
 740             string s = "";
 741             for (int i = 0; i < list.Count; i++)
 742             {
 743                 s += list[i].ToString() + "";
 744             }
 745            // MessageBox.Show((list.Count/10).ToString(), "结果", MessageBoxButtons.OK);
 746         }
 747 
 748         private int selectNum(int start)   //选择下一个要试探填写的数,返回0表示该数已被选择
 749         {
 750             int j;
 751             for (j = start; j <= N; j++)
 752             {
 753                 if (b[j]==1) return j;
 754             }
 755             return 0;
 756         }
 757 
 758         private int check(int pos)  //检测当前位置放入的数是否合理
 759         {
 760             int i, j;
 761             if (pos < 0) return 0;
 762             for (i = 0; (j = checkMatrix[pos,i]) >= 0; i++)
 763             {
 764                 if (!isprime(a[pos] + a[j]))    //i是表示checkMatrix矩阵中pos行第i个数(现总共为3个),j就是该数的实际值,即需要对比的位置
 765                 {
 766                     return 0;
 767                 }
 768             }
 769             return 1;
 770         }
 771 
 772         private int extend(int pos)  //扩展至下一位置
 773         {
 774             a[++pos] = selectNum(1);  //a[pos]即选中的数,因此要把b[a[pos]]置0,表示该数已被选用
 775             b[a[pos]] = 0;
 776             return pos;  //返回下一个位置
 777         }
 778         private int change(int pos)   //改变位置,即回溯至前面的位置
 779         {
 780             int j = selectNum(a[pos] + 1);
 781             while (pos >= 0 && (j = selectNum(a[pos] + 1)) == 0)  //j==0说明所选的数不可用,返回上一个位置pos-1位置
 782             {
 783                 b[a[pos--]] = 1;
 784             }
 785             if (pos < 0) return -1;
 786             b[a[pos]] = 1;
 787             a[pos] = j;
 788             b[j] = 0;
 789             return pos;
 790         }
 791         private void find(List<int> list)  //遍历寻找可行解
 792         {
 793             int ok = 1, pos = 0;
 794             a[pos] = 1; b[a[pos]] = 0;           
 795             do
 796             {
 797                 if (ok == 1)
 798                 {
 799                     if (pos == 8)
 800                     {
 801                         //MessageBox.Show("得到一个解", "结果", MessageBoxButtons.OK);
 802                         write(a,list);
 803                         pos = change(pos);
 804                     }
 805                     else
 806                     {
 807                         pos = extend(pos);  //往下扩展
 808                     }
 809                 }
 810                 else
 811                 {                   
 812                     pos = change(pos);  //如果ok==0,说明所选的数不可行,需要回溯                   
 813                 }
 814                 ok = check(pos);  //检查该数是否符合要求,如果不符合要求则ok=0
 815             } while (pos > 0);
 816         }
 817 
 818         private void button14_Click(object sender, EventArgs e)  //分治法:比赛日程的安排问题
 819         {
 820             int k = 4;  //规模,即有2^k个比赛选手
 821             int N=(int)(Math.Pow(2,k)+1);  //2的k次方加1
 822             int[,] a = new int[N, N-1];  //用于存放结果,行代表选手编号,列代表比赛日
 823             int twoml, twom, i, j, m;
 824             m = 1;
 825             twoml = 1;
 826             a[1, 1] = 2;
 827             a[2, 1] = 1;  //预设两位选手的比赛日程
 828             while (m < k)
 829             {
 830                 m++;    //分治规模,从小到大,m的最大值为k
 831                 twoml += twoml;  //twoml的值随着m的扩大,依次从2、4、8、16……2^(k-1),等于规模数(选手总数)的一半
 832                 twom = 2 * twoml;   //twom的值为4、8、16……2^k,等于规模数(选手总数)
 833                 /*以下填写左下角*/
 834                 for (i = twoml + 1; i <= twom; i++)   //填写左下角,i的值从选手编号的后半第1个数开始
 835                 {
 836                     
 837                     for (j = 1; j <= twoml - 1; j++)   //j的值,即列值(比赛日),从1到规模数一半减1
 838                     {
 839                         
 840                         a[i,j] = a[i - twoml,j] + twoml;  //等于上半对应的值加上规模数的一半
 841                     }
 842                 }
 843                 /*以下填写右上角*/
 844                 a[1,twoml] = twoml + 1;  //填写日程表右上角第一列第1个数,即规模数后半的第1个数
 845                 for (i = 2; i <= twoml; i++)
 846                 {
 847                     a[i,twoml] = a[i - 1, twoml] + 1;   //右上角第一列,第i行等于其上方数加1
 848                 }
 849 
 850                 for (j = twoml + 1; j < twom; j++)   //右上角第2列(twoml+1)至最后一列(twom-1)
 851                 {
 852                     for (i = 1; i < twoml; i++)    //右上角第1行至第twoml-1行
 853                     {
 854                         a[i, j] = a[i + 1, j - 1];   //等于左侧一列左下方的选手编号
 855                     }
 856                     a[twoml, j] = a[1, j - 1];   //右上角每列的最后一行的值等于前一列第一个值
 857                 }
 858                 /*以下填写右下角*/
 859                 for (j = twoml; j < twom; j++)  //j为列编号,从规模数一半开始
 860                 {
 861                     for (i = 1; i <= twoml; i++)  //i为选手编号,右下角只填写前一半选手编号
 862                     {
 863                         a[a[i, j], j] = i;  //a[i,j]代表右上角同一列上第i行的数,按照同列上的第一行的数对应的行开始填数1、2、3……
 864                     }
 865                 }              
 866             }
 867             toDatagrid2(a);
 868         }
 869 
 870         private void button15_Click(object sender, EventArgs e)  //贪心法多机调度问题
 871         {
 872             int[] s = { 16, 14, 6, 5, 4, 3,2 };  //各任务耗时,按从长到短排序
 873             int n = s.Length;   //任务总数量
 874             int m = 3;          //机器数量,小于n
 875             int [] d=new int [m];  //m台机器的时间数组
 876             for (int i = 0; i < m; i++)
 877             {
 878                 d[i] = s[i];    //初始赋值,先选前面最大三个数
 879             }
 880             for (int i = m; i < n; i++)
 881             {
 882                 d[min(d)] += s[i];  //把任务分配给d数组中值最小的数
 883             }
 884 
 885             pa(d, "结果");
 886         }
 887 
 888         private int min(int[] a)  //返回数组中最小数对应的下标
 889         {
 890             int t = 0;
 891             for (int i = 1; i < a.Length; i++)
 892             {
 893                 if (a[t] > a[i])
 894                 {
 895                     t = i;
 896                 }
 897             }
 898             return t;
 899         }
 900 
 901         private void button1_Click(object sender, EventArgs e)  //马的遍历问题,主函数
 902         {
 903             int sx, sy, i, j, step=0, no, start;
 904             List <int [,]> list=new List<int[,]>();
 905             
 906             for (sx = 0; sx < 8; sx++)
 907             {
 908                 for (sy = 0; sy < 8; sy++)
 909                 {
 910                     start = 0;
 911                     do
 912                     {
 913                         for (i = 0; i < 8; i++)
 914                         {
 915                             for (j = 0; j < 8; j++)
 916                             {
 917                                 board[i, j] = 0;   //清棋盘,全部置0
 918                             }
 919                         }
 920                         i = sx;
 921                         j = sy;
 922                         for (step = 1; step <= 64; step++)  //step代表第几步,第1步为起始位置
 923                         {
 924                             if ((no = next(i, j, start)) == -1) break;  //无出口,结束循环,no是下一步最少出口的着数
 925                             i += deltai[no];
 926                             j += deltaj[no];
 927                             board[i, j] = step;
 928                         }
 929                         if (step > 64)   //找到一个可行解
 930                         {
 931                         //将可行解转移到kf,然后绑定到list;不能直接用list.Add(board),因为后面的数组会覆盖前面的数组
 932                             int[,] kf = new int [8,8];        
 933                             for (int ii = 0; ii < 8; ii++)
 934                             {
 935                                 for (int jj = 0; jj < 8; jj++)
 936                                 {
 937                                     kf[ii,jj] = board[ii,jj];
 938                                 }
 939                             }                           
 940                             list.Add(kf);
 941                             break; 
 942                         }
 943                         start++;
 944                     } while (step <= 64);
 945                 }
 946             }
 947             for (int ff = 0; ff < list.Count; ff++)  //逐个显示可行解,一共64个
 948             {
 949                 MessageBox.Show(ff.ToString(), "序号", MessageBoxButtons.OK);
 950                 toDatagrid2(list[ff]);
 951             }
 952         }
 953 
 954         private int exitn(int i, int j, int s, int[] a)  //求(i,j)的出口数,s为着数
 955         {
 956             int i1, j1, k, count;
 957             for (count = k = 0; k < 8; k++)
 958             {
 959                 i1 = i + deltai[k];
 960                 j1 = j + deltaj[k];
 961                 if (i1 >= 0 && i1 < 8 && j1 >= 0 && j1 < 8 && board[i1, j1] == 0)  //下一着的位置须符合不出界、且是马尚未走过的位置
 962                 {
 963                     a[count++] = k;
 964                 }
 965             }
 966             return count;
 967         }
 968         private int next(int i, int j, int s)    //选下一出口,即求出坐标为(i,j)、起始着数为s的下一出口数量最少的着数
 969         {
 970             int m, k, kk=0, min, temp;
 971             int[] a = new int[8];
 972             int[] b = new int[8];
 973             m = exitn(i, j, s, a);   //坐标为(i,j),着数为s,的马的出口数量, a存放着可行着数
 974             if (m == 0) return -1;   //无出口,返回-1
 975             for (min = 9, k = 0; k < m; k++)  //寻找可行着数中,下一出口最小的着数
 976             {
 977                 temp = exitn(i + deltai[a[k]], j + deltaj[a[k]], s, b);
 978                 if (temp < min)
 979                 {
 980                     min = temp;
 981                     kk = a[k];
 982                 }
 983             }
 984             return kk;
 985         }
 986 
 987         private void button16_Click(object sender, EventArgs e)   //贪心法装箱问题
 988         {
 989             int[] ele = {60,45,35,20,20,20 };  //物品体积
 990             int [] box=new int [ele.Length];   //准备箱子
 991             string[] list = new string[ele.Length];
 992             string s = "";
 993             int boxcount = 0;
 994             for (int i = 0; i < ele.Length; i++)
 995             {
 996                 box[i] = 100;   //每个箱子容量为100
 997             }
 998             for (int i = 0; i < ele.Length; i++)
 999             {
1000                 for (int j = 0; j < box.Length; j++)
1001                 {
1002                     if (ele[i] < box[j])
1003                     {
1004                         box[j] -= ele[i];   //放入箱子
1005                         list[j] += (i+1).ToString() + "";  //记录每个箱子装哪些物品,物品编号从1开始
1006                         break;
1007                     }
1008                 }
1009             }
1010             for (int i = 0; i < ele.Length; i++)  //显示结果
1011             {
1012                 if (list[i] != null)
1013                 {
1014                     s += list[i].Substring(0,list[i].Length-1) + "";
1015                     boxcount++;
1016                 }
1017             }
1018             MessageBox.Show(boxcount.ToString(), "使用的箱子数量", MessageBoxButtons.OK);
1019             MessageBox.Show(s, "每个箱子装入的物品编号", MessageBoxButtons.OK);
1020         }
1021 
1022         
1023     }

 

posted @ 2021-10-23 14:13  wwwzgy  阅读(1043)  评论(0)    收藏  举报