分治算法

使用分治法设计程序时,一般可按以下步骤进行:
(1)分解:将要求解的问题划分成若干规模较小的同类问题
(2)求解:当子问题划分得足够小时,用较简单的方法解决
(3)合并:按求解问题的要求,将子问题的解逐层合并,即可构成最终的解

分治算法实例(乒乓球比赛赛程安排):

我们要给八个人安排赛程 每个人都要对战 并在七天全部比完

image

我们可以先把它分成一半 也就是分解这个过程

image

然后再分解 这时候 这已经分得最小了 那么也只有这么一种安排 也就是 求解

image

那么回到上一步 也就是合并

image

再把这一步往上 那么就是最开始的那张结果图

程序实现:

#include <stdio.h>
#define MAXN 64
int a[MAXN+1][MAXN+1]={0};
void gamecal(int k,int n)//处理编号k开始的n个选手的日程 
{
    int i,j;
    if(n==2)
    {
        a[k][1]=k;  //参赛选手编号
        a[k][2]=k+1; //对阵选手编号
        a[k+1][1]=k+1; //参赛选手编号 
        a[k+1][2]=k; //对阵选手编号 
    }else{
        gamecal(k,n/2);
        gamecal(k+n/2,n/2);
        for(i=k;i<k+n/2;i++) //填充右上角 
        {
            for(j=n/2+1;j<=n;j++)
            {
                a[i][j]=a[i+n/2][j-n/2];
            }
        }
        for(i=k+n/2;i<k+n;i++) //填充左下角 
        {
            for(j=n/2+1;j<=n;j++)
            {
                a[i][j]=a[i-n/2][j-n/2];
            }
        }
    }
}
  
int main()
{
    int m,i,j;
    printf("输入参赛选手人数:");
    scanf("%d",&m);
    j=2;
    for(i=2;i<8;i++)
    {
        j=j*2;
        if(j==m) break;
    }
    if(i>=8)
    {
        printf("参赛选手人数必须为2的整数次幂,且不超过64!\n");
        getch();
        return 0; 
    }
    gamecal(1,m);
    printf("\n编号 ");
    for(i=2;i<=m;i++)
        printf("%2d天 ",i-1);
    printf("\n");
    for(i=1;i<=m;i++)
    {
       for(j=1;j<=m;j++)
           printf("%4d ",a[i][j]);
       printf("\n");
    }
    getch();
    return 0;    
}

 

结果:

image

 


贪婪算法

      贪婪算法基本思路:从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快地求得更好的解。当达到算法中的某一步不能再继续前进时,就停止算法,给出近似解。
      由贪婪算法的特点和思路可看出,该算法存在以下问题:
        ⊙ 不能保证最后的解是最优的
        ⊙ 不能用来求最大或最小解问题
        ⊙ 只能求满足某些约束条件的可行解的范围

分治算法实例(找零钱):

image

 

程序实现:

        //为方便计算 把钱都转化为分 即乘上100
        private static int[] parvalue = new int[9] {10000, 5000, 1000, 500, 200, 100, 50, 20, 10};
        //此来存储每种钱币的数量
        private static int[] num = new int[9];

        //计算的方法
        private static void Exchange(int n)
        {
            int i;
            for (i = 0; i < 9; i++)  if (n > parvalue[i]) break;
            while (n > 0 && i < 9)
            {
                if (n >= parvalue[i])
                {
                    n -= parvalue[i];
                    num[i]++;
                }
                else if (n < 10 && n >= 5)
                {
                    num[9 - 1]++;
                    break;
                }
                else i++;
            }
        }

        static void Main(string[] args)
        {
            Console.WriteLine("请输入找零的金额:");
            float m = float.Parse(Console.ReadLine());
            Exchange((int) (100*m));
            Console.WriteLine(m+"元零钱的的组成为:");
            for (int j = 0; j < 9; j++)
            {
                if (num[j] > 0)
                {
                    Console.WriteLine(num[j] + "" + (float) parvalue[j]/100);
                }
            }
            Console.ReadKey();
        }

结果:

image


试探算法

    为了求得问题的解,先选择某一种可能情况进行试探,在试探过程中,一旦发现原来的选择的假设情况是错误的,就退回一步重新选择,继续向前试探,如此反复进行,直至得到解或证明无解

试探算法实例:

image

 

程序实现:

       private static int MAXN = 7;//设置每一注彩票的位数
        private static int NUM = 29;//设置组成彩票的数字
        private static int[] num = new int[NUM];
       private static int[] lottery = new int[MAXN];

       private static void Combine(int n, int m)
        {
            int i, j;
            for (i = n; i >= m; i--)
            {
                lottery[m - 1] = num[i - 1]; //保存一位数字 
                if (m > 1) Combine(i - 1, m - 1);
                else                         //若m=1,输出一注号码
                {
                    for (j = MAXN-1; j >= 0; j--)
                    {
                        Console.Write(lottery[j]+" ");
                    }
                    Console.WriteLine();
                }
            }
            Console.ReadKey();
        }

        static void Main(string[] args)
        {
            int i;
            for (i = 0; i < NUM; i++)  //设置彩票各位数字 
                num[i] = i + 1;
            for (i = 0; i < MAXN; i++)
                lottery[i] = 0;
            Combine(NUM, MAXN);
        }

结果:

image

 


模拟算法

在程序设计语言中,可使用随机函数来模拟自然界中发生的不可预测情况

模拟算法实例一(猜数字):

         使用模拟法编写一个猜数游戏,由计算机随机生成一个1~100之内的整数,然后由用户来猜这个数,根据用户猜测的次数分别给出不同的提示文字

程序实现:

        private static Random newNum = new Random();
        private static int myNum = newNum.Next(1, 99);
        private static void Main(string[] args)
        {
            int n = 0, m = 0, i = 0;
            n = myNum;
            do
            {
                Console.WriteLine("输入所猜数字:");
                m = int.Parse(Console.ReadLine());
                i++;
                if (m > n)
                    Console.WriteLine("错误!所猜数太大了!");
                else if (m < n)
                    Console.WriteLine("错误!所猜数太小了!");
            } while (m != n);
                Console.WriteLine("答对了!");
                Console.WriteLine("共猜测了" + i + "");
                if (i <= 5)
                    Console.WriteLine("你太聪明了,这么快就猜出来了!");
                else if (i > 5)
                    Console.WriteLine("还需改进方法,以便更快猜出来!");

            Console.ReadKey();
        }

结果:

image

 

 

模拟算法实例二:

模拟掷骰子游戏

    由用户输入骰子数量和参赛人数,然后由计算机随机生成每一粒骰子的数量,再累加起来就得到每一个选手的总点数

 

程序实现:

       //产生随机骰子的方法
        private static void Play(int n)
        {
            Random newMun = new Random();
            int i, m = 0, t = 0;
            for (i = 0; i < n; i++)
            {             
                t = newMun.Next(1, 6);
                m += t;
                Console.WriteLine("" + (i + 1) + "粒为:" + t);
            }
            Console.WriteLine("总点数为" + m);
            Console.ReadKey();
        }

        static void Main(string[] args)
        {
            int c;//参赛人数
            int n;//骰子数量 
            int i, m;
            do
            {
                Console.WriteLine("设置骰子数量(输入0退出):");
                n = int.Parse(Console.ReadLine());
                if (n == 0) break; //至少一个骰子 
                Console.WriteLine("输入本轮参赛人数(输入0退出):");
                c = int.Parse(Console.ReadLine());
                if (c == 0) break;
                for (i = 0; i < c; i++)
                {
                    Console.WriteLine("" + (i + 1) + "位选手掷出的骰子为:");
                    Play(n);
                }
            } while (true);
            Console.ReadKey();
        }

 

结果:

image


算法评价原则

  正确性
  高效性
  空间性
  可读性

算法的效率 

  通常认为,通过统计算法中基本操作重复执行的次数就可近似地得到算法的执行效率,用O(n)表示,称为时间复杂度

 

posted on 2016-03-03 18:14  青菜蘑菇汤  阅读(353)  评论(0编辑  收藏  举报